Skip to content

Commit 67e516c

Browse files
committed
rollup merge of rust-lang#23269: shepmaster/split-not-double-ended
Closes rust-lang#23262
2 parents ec1a85a + c6ca220 commit 67e516c

File tree

3 files changed

+188
-39
lines changed

3 files changed

+188
-39
lines changed

src/libcollections/str.rs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ use slice::SliceConcatExt;
7474

7575
pub use core::str::{FromStr, Utf8Error, Str};
7676
pub use core::str::{Lines, LinesAny, MatchIndices, SplitStr, CharRange};
77-
pub use core::str::{Split, SplitTerminator};
78-
pub use core::str::{SplitN, RSplitN};
77+
pub use core::str::{Split, SplitTerminator, SplitN};
78+
pub use core::str::{RSplit, RSplitN};
7979
pub use core::str::{from_utf8, CharEq, Chars, CharIndices, Bytes};
8080
pub use core::str::{from_utf8_unchecked, from_c_str, ParseBoolError};
8181
pub use unicode::str::{Words, Graphemes, GraphemeIndices};
@@ -699,23 +699,48 @@ impl str {
699699
core_str::StrExt::split_terminator(&self[..], pat)
700700
}
701701

702-
/// An iterator over substrings of `self`, separated by characters matched by a pattern,
702+
/// An iterator over substrings of `self`, separated by a pattern,
703703
/// starting from the end of the string.
704704
///
705-
/// Restricted to splitting at most `count` times.
705+
/// # Examples
706706
///
707-
/// The pattern can be a simple `&str`, or a closure that determines the split.
707+
/// Simple patterns:
708+
///
709+
/// ```
710+
/// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect();
711+
/// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]);
712+
///
713+
/// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect();
714+
/// assert_eq!(v, ["leopard", "tiger", "lion"]);
715+
/// ```
716+
///
717+
/// More complex patterns with a lambda:
718+
///
719+
/// ```
720+
/// let v: Vec<&str> = "abc1def2ghi".rsplit(|c: char| c.is_numeric()).collect();
721+
/// assert_eq!(v, ["ghi", "def", "abc"]);
722+
/// ```
723+
#[stable(feature = "rust1", since = "1.0.0")]
724+
pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
725+
where P::Searcher: ReverseSearcher<'a>
726+
{
727+
core_str::StrExt::rsplit(&self[..], pat)
728+
}
729+
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.
708733
///
709734
/// # Examples
710735
///
711-
/// Simple `&str` patterns:
736+
/// Simple patterns:
712737
///
713738
/// ```
714739
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
715740
/// assert_eq!(v, ["lamb", "little", "Mary had a"]);
716741
///
717-
/// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn(2, 'X').collect();
718-
/// assert_eq!(v, ["leopard", "tiger", "lionX"]);
742+
/// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
743+
/// assert_eq!(v, ["leopard", "lion::tiger"]);
719744
/// ```
720745
///
721746
/// More complex patterns with a lambda:
@@ -725,7 +750,9 @@ impl str {
725750
/// assert_eq!(v, ["ghi", "abc1def"]);
726751
/// ```
727752
#[stable(feature = "rust1", since = "1.0.0")]
728-
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+
{
729756
core_str::StrExt::rsplitn(&self[..], count, pat)
730757
}
731758

src/libcollectionstest/str.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,34 @@ fn test_split_char_iterator_no_trailing() {
910910
assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
911911
}
912912

913+
#[test]
914+
fn test_rsplit() {
915+
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
916+
917+
let split: Vec<&str> = data.rsplit(' ').collect();
918+
assert_eq!(split, ["lämb\n", "lämb\nLittle", "little", "ä", "häd", "\nMäry"]);
919+
920+
let split: Vec<&str> = data.rsplit("lämb").collect();
921+
assert_eq!(split, ["\n", "\nLittle ", "\nMäry häd ä little "]);
922+
923+
let split: Vec<&str> = data.rsplit(|c: char| c == 'ä').collect();
924+
assert_eq!(split, ["mb\n", "mb\nLittle l", " little l", "d ", "ry h", "\nM"]);
925+
}
926+
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+
913941
#[test]
914942
fn test_words() {
915943
let data = "\n \tMäry häd\tä little lämb\nLittle lämb\n";

src/libcore/str/mod.rs

Lines changed: 124 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,24 @@ macro_rules! delegate_iter {
111111
self.0.size_hint()
112112
}
113113
}
114-
}
114+
};
115+
(pattern reverse $te:ty : $ti:ty) => {
116+
#[stable(feature = "rust1", since = "1.0.0")]
117+
impl<'a, P: Pattern<'a>> Iterator for $ti
118+
where P::Searcher: ReverseSearcher<'a>
119+
{
120+
type Item = $te;
121+
122+
#[inline]
123+
fn next(&mut self) -> Option<$te> {
124+
self.0.next()
125+
}
126+
#[inline]
127+
fn size_hint(&self) -> (usize, Option<usize>) {
128+
self.0.size_hint()
129+
}
130+
}
131+
};
115132
}
116133

117134
/// A trait to abstract the idea of creating a new instance of a type from a
@@ -550,7 +567,26 @@ struct CharSplitsN<'a, P: Pattern<'a>> {
550567
iter: CharSplits<'a, P>,
551568
/// The number of splits remaining
552569
count: usize,
553-
invert: bool,
570+
}
571+
572+
/// An iterator over the substrings of a string, separated by a
573+
/// pattern, in reverse order.
574+
struct RCharSplits<'a, P: Pattern<'a>> {
575+
/// The slice remaining to be iterated
576+
start: usize,
577+
end: usize,
578+
matcher: P::Searcher,
579+
/// Whether an empty string at the end of iteration is allowed
580+
allow_final_empty: bool,
581+
finished: bool,
582+
}
583+
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,
554590
}
555591

556592
/// An iterator over the lines of a string, separated by `\n`.
@@ -631,21 +667,74 @@ where P::Searcher: DoubleEndedSearcher<'a> {
631667
}
632668

633669
#[stable(feature = "rust1", since = "1.0.0")]
634-
impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P>
635-
where P::Searcher: DoubleEndedSearcher<'a> {
670+
impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> {
636671
type Item = &'a str;
637672

638673
#[inline]
639674
fn next(&mut self) -> Option<&'a str> {
640675
if self.count != 0 {
641676
self.count -= 1;
642-
if self.invert { self.iter.next_back() } else { self.iter.next() }
677+
self.iter.next()
643678
} else {
644679
self.iter.get_end()
645680
}
646681
}
647682
}
648683

684+
impl<'a, P: Pattern<'a>> RCharSplits<'a, P> {
685+
#[inline]
686+
fn get_remainder(&mut self) -> Option<&'a str> {
687+
if !self.finished && (self.allow_final_empty || self.end - self.start > 0) {
688+
self.finished = true;
689+
unsafe {
690+
let string = self.matcher.haystack().slice_unchecked(self.start, self.end);
691+
Some(string)
692+
}
693+
} else {
694+
None
695+
}
696+
}
697+
}
698+
699+
#[stable(feature = "rust1", since = "1.0.0")]
700+
impl<'a, P: Pattern<'a>> Iterator for RCharSplits<'a, P>
701+
where P::Searcher: ReverseSearcher<'a>
702+
{
703+
type Item = &'a str;
704+
705+
#[inline]
706+
fn next(&mut self) -> Option<&'a str> {
707+
if self.finished { return None }
708+
709+
let haystack = self.matcher.haystack();
710+
match self.matcher.next_match_back() {
711+
Some((a, b)) => unsafe {
712+
let elt = haystack.slice_unchecked(b, self.end);
713+
self.end = a;
714+
Some(elt)
715+
},
716+
None => self.get_remainder(),
717+
}
718+
}
719+
}
720+
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+
649738
/// The internal state of an iterator that searches for matches of a substring
650739
/// within a larger string using two-way search
651740
#[derive(Clone)]
@@ -1293,23 +1382,7 @@ impl<'a, S: ?Sized> Str for &'a S where S: Str {
12931382
/// Return type of `StrExt::split`
12941383
#[stable(feature = "rust1", since = "1.0.0")]
12951384
pub struct Split<'a, P: Pattern<'a>>(CharSplits<'a, P>);
1296-
#[stable(feature = "rust1", since = "1.0.0")]
1297-
impl<'a, P: Pattern<'a>> Iterator for Split<'a, P> {
1298-
type Item = &'a str;
1299-
1300-
#[inline]
1301-
fn next(&mut self) -> Option<&'a str> {
1302-
self.0.next()
1303-
}
1304-
}
1305-
#[stable(feature = "rust1", since = "1.0.0")]
1306-
impl<'a, P: Pattern<'a>> DoubleEndedIterator for Split<'a, P>
1307-
where P::Searcher: DoubleEndedSearcher<'a> {
1308-
#[inline]
1309-
fn next_back(&mut self) -> Option<&'a str> {
1310-
self.0.next_back()
1311-
}
1312-
}
1385+
delegate_iter!{pattern &'a str : Split<'a, P>}
13131386

13141387
/// Return type of `StrExt::split_terminator`
13151388
#[stable(feature = "rust1", since = "1.0.0")]
@@ -1321,10 +1394,15 @@ delegate_iter!{pattern &'a str : SplitTerminator<'a, P>}
13211394
pub struct SplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
13221395
delegate_iter!{pattern forward &'a str : SplitN<'a, P>}
13231396

1397+
/// Return type of `StrExt::rsplit`
1398+
#[stable(feature = "rust1", since = "1.0.0")]
1399+
pub struct RSplit<'a, P: Pattern<'a>>(RCharSplits<'a, P>);
1400+
delegate_iter!{pattern reverse &'a str : RSplit<'a, P>}
1401+
13241402
/// Return type of `StrExt::rsplitn`
13251403
#[stable(feature = "rust1", since = "1.0.0")]
1326-
pub struct RSplitN<'a, P: Pattern<'a>>(CharSplitsN<'a, P>);
1327-
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>}
13281406

13291407
/// Methods for string slices
13301408
#[allow(missing_docs)]
@@ -1340,7 +1418,10 @@ pub trait StrExt {
13401418
fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>;
13411419
fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>;
13421420
fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>;
1343-
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>;
1421+
fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
1422+
where P::Searcher: ReverseSearcher<'a>;
1423+
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P>
1424+
where P::Searcher: ReverseSearcher<'a>;
13441425
fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>;
13451426
#[allow(deprecated) /* for SplitStr */]
13461427
fn split_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitStr<'a, P>;
@@ -1424,7 +1505,6 @@ impl StrExt for str {
14241505
SplitN(CharSplitsN {
14251506
iter: self.split(pat).0,
14261507
count: count,
1427-
invert: false,
14281508
})
14291509
}
14301510

@@ -1437,11 +1517,25 @@ impl StrExt for str {
14371517
}
14381518

14391519
#[inline]
1440-
fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> {
1441-
RSplitN(CharSplitsN {
1442-
iter: self.split(pat).0,
1520+
fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
1521+
where P::Searcher: ReverseSearcher<'a>
1522+
{
1523+
RSplit(RCharSplits {
1524+
start: 0,
1525+
end: self.len(),
1526+
matcher: pat.into_searcher(self),
1527+
allow_final_empty: true,
1528+
finished: false,
1529+
})
1530+
}
1531+
1532+
#[inline]
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,
14431538
count: count,
1444-
invert: true,
14451539
})
14461540
}
14471541

0 commit comments

Comments
 (0)