Skip to content

Commit c6ca220

Browse files
committed
StrExt::splitn should not require a DoubleEndedSearcher
Closes #23262
1 parent 6a5148b commit c6ca220

File tree

3 files changed

+59
-39
lines changed

3 files changed

+59
-39
lines changed

src/libcollections/str.rs

+9-10
Original file line numberDiff line numberDiff line change
@@ -727,23 +727,20 @@ impl str {
727727
core_str::StrExt::rsplit(&self[..], pat)
728728
}
729729

730-
/// An iterator over substrings of `self`, separated by characters matched by a pattern,
731-
/// starting from the end of the string.
732-
///
733-
/// Restricted to splitting at most `count` times.
734-
///
735-
/// The pattern can be a simple `&str`, or a closure that determines the split.
730+
/// An iterator over substrings of `self`, separated by a pattern,
731+
/// starting from the end of the string, restricted to splitting
732+
/// at most `count` times.
736733
///
737734
/// # Examples
738735
///
739-
/// Simple `&str` patterns:
736+
/// Simple patterns:
740737
///
741738
/// ```
742739
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
743740
/// assert_eq!(v, ["lamb", "little", "Mary had a"]);
744741
///
745-
/// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
746-
/// assert_eq!(v, ["leopard", "tiger", "lionX"]);
742+
/// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
743+
/// assert_eq!(v, ["leopard", "lion::tiger"]);
747744
/// ```
748745
///
749746
/// More complex patterns with a lambda:
@@ -753,7 +750,9 @@ impl str {
753750
/// assert_eq!(v, ["ghi", "abc1def"]);
754751
/// ```
755752
#[stable(feature = "rust1", since = "1.0.0")]
756-
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
753+
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
754+
where P::Searcher: ReverseSearcher<'a>
755+
{
757756
core_str::StrExt::rsplitn(&self[..], count, pat)
758757
}
759758

src/libcollectionstest/str.rs

+14
Original file line numberDiff line numberDiff line change
@@ -924,6 +924,20 @@ fn test_rsplit() {
924924
assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
925925
}
926926

927+
#[test]
928+
fn test_rsplitn() {
929+
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
930+
931+
let split: Vec<&str> = data.rsplitn(1, ' ').collect();
932+
assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
933+
934+
let split: Vec<&str> = data.rsplitn(1, "lämb").collect();
935+
assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
936+
937+
let split: Vec<&str> = data.rsplitn(1, |c: char| c == 'ä').collect();
938+
assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
939+
}
940+
927941
#[test]
928942
fn test_words() {
929943
let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";

src/libcore/str/mod.rs

+36-29
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,6 @@ struct CharSplitsN<'a, P: Pattern<'a>> {
567567
iter: CharSplits<'a, P>,
568568
/// The number of splits remaining
569569
count: usize,
570-
invert: bool,
571570
}
572571

573572
/// An iterator over the substrings of a string, separated by a
@@ -582,6 +581,13 @@ struct RCharSplits<'a, P: Pattern<'a>> {
582581
finished: bool,
583582
}
584583

584+
/// An iterator over the substrings of a string, separated by a
585+
/// pattern, splitting at most `count` times, in reverse order.
586+
struct RCharSplitsN<'a, P: Pattern<'a>> {
587+
iter: RCharSplits<'a, P>,
588+
/// The number of splits remaining
589+
count: usize,
590+
}
585591

586592
/// An iterator over the lines of a string, separated by `\n`.
587593
#[stable(feature = "rust1", since = "1.0.0")]
@@ -661,15 +667,14 @@ where P::Searcher: DoubleEndedSearcher<'a> {
661667
}
662668

663669
#[stable(feature = "rust1", since = "1.0.0")]
664-
impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P>
665-
where P::Searcher: DoubleEndedSearcher<'a> {
670+
impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> {
666671
type Item = &'a str;
667672

668673
#[inline]
669674
fn next(&mut self) -> Option<&'a str> {
670675
if self.count != 0 {
671676
self.count -= 1;
672-
if self.invert { self.iter.next_back() } else { self.iter.next() }
677+
self.iter.next()
673678
} else {
674679
self.iter.get_end()
675680
}
@@ -713,6 +718,23 @@ impl<'a, P: Pattern<'a>> Iterator for RCharSplits<'a, P>
713718
}
714719
}
715720

721+
#[stable(feature = "rust1", since = "1.0.0")]
722+
impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P>
723+
where P::Searcher: ReverseSearcher<'a>
724+
{
725+
type Item = &'a str;
726+
727+
#[inline]
728+
fn next(&mut self) -> Option<&'a str> {
729+
if self.count != 0 {
730+
self.count -= 1;
731+
self.iter.next()
732+
} else {
733+
self.iter.get_remainder()
734+
}
735+
}
736+
}
737+
716738
/// The internal state of an iterator that searches for matches of a substring
717739
/// within a larger string using two-way search
718740
#[derive(Clone)]
@@ -1360,23 +1382,7 @@ impl<'a, S: ?Sized> Str for &'a S where S: Str {
13601382
/// Return type of `StrExt::split`
13611383
#[stable(feature = "rust1", since = "1.0.0")]
13621384
pub struct Split<'a, P: Pattern<'a>>(CharSplits<'a, P>);
1363-
#[stable(feature = "rust1", since = "1.0.0")]
1364-
impl<'a, P: Pattern<'a>> Iterator for Split<'a, P> {
1365-
type Item = &'a str;
1366-
1367-
#[inline]
1368-
fn next(&mut self) -> Option<&'a str> {
1369-
self.0.next()
1370-
}
1371-
}
1372-
#[stable(feature = "rust1", since = "1.0.0")]
1373-
impl<'a, P: Pattern<'a>> DoubleEndedIterator for Split<'a, P>
1374-
where P::Searcher: DoubleEndedSearcher<'a> {
1375-
#[inline]
1376-
fn next_back(&mut self) -> Option<&'a str> {
1377-
self.0.next_back()
1378-
}
1379-
}
1385+
delegate_iter!{pattern &'a str : Split<'a, P>}
13801386

13811387
/// Return type of `StrExt::split_terminator`
13821388
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1395,8 +1401,8 @@ delegate_iter!{pattern reverse &'a str : RSplit<'a, P>}
13951401

13961402
/// Return type of `StrExt::rsplitn`
13971403
#[stable(feature = "rust1", since = "1.0.0")]
1398-
pub struct RSplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
1399-
delegate_iter!{pattern forward &'a str : RSplitN<'a, P>}
1404+
pub struct RSplitN<'a, P: Pattern<'a>>(RCharSplitsN<'a, P>);
1405+
delegate_iter!{pattern reverse &'a str : RSplitN<'a, P>}
14001406

14011407
/// Methods for string slices
14021408
#[allow(missing_docs)]
@@ -1414,7 +1420,8 @@ pub trait StrExt {
14141420
fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
14151421
fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
14161422
where P::Searcher: ReverseSearcher<'a>;
1417-
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>;
1423+
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
1424+
where P::Searcher: ReverseSearcher<'a>;
14181425
fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
14191426
#[allow(deprecated) /* for SplitStr */]
14201427
fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P>;
@@ -1498,7 +1505,6 @@ impl StrExt for str {
14981505
SplitN(CharSplitsN {
14991506
iter: self.split(pat).0,
15001507
count: count,
1501-
invert: false,
15021508
})
15031509
}
15041510

@@ -1524,11 +1530,12 @@ impl StrExt for str {
15241530
}
15251531

15261532
#[inline]
1527-
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
1528-
RSplitN(CharSplitsN {
1529-
iter: self.split(pat).0,
1533+
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
1534+
where P::Searcher: ReverseSearcher<'a>
1535+
{
1536+
RSplitN(RCharSplitsN {
1537+
iter: self.rsplit(pat).0,
15301538
count: count,
1531-
invert: true,
15321539
})
15331540
}
15341541

0 commit comments

Comments
 (0)