Skip to content

Commit e9bacba

Browse files
committed
rollup merge of #23951: alexcrichton/splitn
This commit is an implementation of [RFC 979][rfc] which changes the meaning of the count parameter to the `splitn` function on strings and slices. The parameter now means the number of items that are returned from the iterator, not the number of splits that are made. [rfc]: rust-lang/rfcs#979 Closes #23911 [breaking-change]
2 parents fb4029f + e98dce3 commit e9bacba

File tree

14 files changed

+85
-66
lines changed

14 files changed

+85
-66
lines changed

src/compiletest/header.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
311311
parse_name_value_directive(line, "exec-env").map(|nv| {
312312
// nv is either FOO or FOO=BAR
313313
let mut strs: Vec<String> = nv
314-
.splitn(1, '=')
314+
.splitn(2, '=')
315315
.map(|s| s.to_string())
316316
.collect();
317317

src/libcollections/slice.rs

+18-6
Original file line numberDiff line numberDiff line change
@@ -328,17 +328,20 @@ impl<T> [T] {
328328
}
329329

330330
/// Returns an iterator over subslices separated by elements that match
331-
/// `pred`, limited to splitting at most `n` times. The matched element is
331+
/// `pred`, limited to returning at most `n` items. The matched element is
332332
/// not contained in the subslices.
333333
///
334+
/// The last element returned, if any, will contain the remainder of the
335+
/// slice.
336+
///
334337
/// # Examples
335338
///
336339
/// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`,
337340
/// `[20, 60, 50]`):
338341
///
339342
/// ```
340343
/// let v = [10, 40, 30, 20, 60, 50];
341-
/// for group in v.splitn(1, |num| *num % 3 == 0) {
344+
/// for group in v.splitn(2, |num| *num % 3 == 0) {
342345
/// println!("{:?}", group);
343346
/// }
344347
/// ```
@@ -349,18 +352,21 @@ impl<T> [T] {
349352
}
350353

351354
/// Returns an iterator over subslices separated by elements that match
352-
/// `pred` limited to splitting at most `n` times. This starts at the end of
355+
/// `pred` limited to returning at most `n` items. This starts at the end of
353356
/// the slice and works backwards. The matched element is not contained in
354357
/// the subslices.
355358
///
359+
/// The last element returned, if any, will contain the remainder of the
360+
/// slice.
361+
///
356362
/// # Examples
357363
///
358364
/// Print the slice split once, starting from the end, by numbers divisible
359365
/// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
360366
///
361367
/// ```
362368
/// let v = [10, 40, 30, 20, 60, 50];
363-
/// for group in v.rsplitn(1, |num| *num % 3 == 0) {
369+
/// for group in v.rsplitn(2, |num| *num % 3 == 0) {
364370
/// println!("{:?}", group);
365371
/// }
366372
/// ```
@@ -626,8 +632,11 @@ impl<T> [T] {
626632
}
627633

628634
/// Returns an iterator over subslices separated by elements that match
629-
/// `pred`, limited to splitting at most `n` times. The matched element is
635+
/// `pred`, limited to returning at most `n` items. The matched element is
630636
/// not contained in the subslices.
637+
///
638+
/// The last element returned, if any, will contain the remainder of the
639+
/// slice.
631640
#[stable(feature = "rust1", since = "1.0.0")]
632641
#[inline]
633642
pub fn splitn_mut<F>(&mut self, n: usize, pred: F) -> SplitNMut<T, F>
@@ -636,9 +645,12 @@ impl<T> [T] {
636645
}
637646

638647
/// Returns an iterator over subslices separated by elements that match
639-
/// `pred` limited to splitting at most `n` times. This starts at the end of
648+
/// `pred` limited to returning at most `n` items. This starts at the end of
640649
/// the slice and works backwards. The matched element is not contained in
641650
/// the subslices.
651+
///
652+
/// The last element returned, if any, will contain the remainder of the
653+
/// slice.
642654
#[stable(feature = "rust1", since = "1.0.0")]
643655
#[inline]
644656
pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>

src/libcollections/str.rs

+17-11
Original file line numberDiff line numberDiff line change
@@ -610,24 +610,27 @@ impl str {
610610
core_str::StrExt::split(&self[..], pat)
611611
}
612612

613-
/// An iterator over substrings of `self`, separated by characters matched by a pattern,
614-
/// restricted to splitting at most `count` times.
613+
/// An iterator over substrings of `self`, separated by characters matched
614+
/// by a pattern, returning most `count` items.
615615
///
616616
/// The pattern can be a simple `&str`, or a closure that determines
617617
/// the split.
618618
///
619+
/// The last element returned, if any, will contain the remainder of the
620+
/// string.
621+
///
619622
/// # Examples
620623
///
621624
/// Simple `&str` patterns:
622625
///
623626
/// ```
624627
/// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
625-
/// assert_eq!(v, ["Mary", "had", "a little lambda"]);
628+
/// assert_eq!(v, ["Mary", "had a little lambda"]);
626629
///
627630
/// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect();
628-
/// assert_eq!(v, ["lion", "", "tigerXleopard"]);
631+
/// assert_eq!(v, ["lion", "XtigerXleopard"]);
629632
///
630-
/// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect();
633+
/// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
631634
/// assert_eq!(v, ["abcXdef"]);
632635
///
633636
/// let v: Vec<&str> = "".splitn(1, 'X').collect();
@@ -637,7 +640,7 @@ impl str {
637640
/// More complex patterns with a lambda:
638641
///
639642
/// ```
640-
/// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect();
643+
/// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect();
641644
/// assert_eq!(v, ["abc", "def2ghi"]);
642645
/// ```
643646
#[stable(feature = "rust1", since = "1.0.0")]
@@ -705,25 +708,28 @@ impl str {
705708
}
706709

707710
/// An iterator over substrings of `self`, separated by a pattern,
708-
/// starting from the end of the string, restricted to splitting
709-
/// at most `count` times.
711+
/// starting from the end of the string, restricted to returning
712+
/// at most `count` items.
713+
///
714+
/// The last element returned, if any, will contain the remainder of the
715+
/// string.
710716
///
711717
/// # Examples
712718
///
713719
/// Simple patterns:
714720
///
715721
/// ```
716-
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
722+
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
717723
/// assert_eq!(v, ["lamb", "little", "Mary had a"]);
718724
///
719-
/// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
725+
/// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
720726
/// assert_eq!(v, ["leopard", "lion::tiger"]);
721727
/// ```
722728
///
723729
/// More complex patterns with a lambda:
724730
///
725731
/// ```
726-
/// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect();
732+
/// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect();
727733
/// assert_eq!(v, ["ghi", "abc1def"]);
728734
/// ```
729735
#[stable(feature = "rust1", since = "1.0.0")]

src/libcollectionstest/slice.rs

+13-12
Original file line numberDiff line numberDiff line change
@@ -867,37 +867,37 @@ fn test_splitnator() {
867867
let xs = &[1,2,3,4,5];
868868

869869
let splits: &[&[_]] = &[&[1,2,3,4,5]];
870-
assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
870+
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
871871
splits);
872872
let splits: &[&[_]] = &[&[1], &[3,4,5]];
873-
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
873+
assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
874874
splits);
875875
let splits: &[&[_]] = &[&[], &[], &[], &[4,5]];
876-
assert_eq!(xs.splitn(3, |_| true).collect::<Vec<_>>(),
876+
assert_eq!(xs.splitn(4, |_| true).collect::<Vec<_>>(),
877877
splits);
878878

879879
let xs: &[i32] = &[];
880880
let splits: &[&[i32]] = &[&[]];
881-
assert_eq!(xs.splitn(1, |x| *x == 5).collect::<Vec<_>>(), splits);
881+
assert_eq!(xs.splitn(2, |x| *x == 5).collect::<Vec<_>>(), splits);
882882
}
883883

884884
#[test]
885885
fn test_splitnator_mut() {
886886
let xs = &mut [1,2,3,4,5];
887887

888888
let splits: &[&mut[_]] = &[&mut [1,2,3,4,5]];
889-
assert_eq!(xs.splitn_mut(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
889+
assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
890890
splits);
891891
let splits: &[&mut[_]] = &[&mut [1], &mut [3,4,5]];
892-
assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
892+
assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
893893
splits);
894894
let splits: &[&mut[_]] = &[&mut [], &mut [], &mut [], &mut [4,5]];
895-
assert_eq!(xs.splitn_mut(3, |_| true).collect::<Vec<_>>(),
895+
assert_eq!(xs.splitn_mut(4, |_| true).collect::<Vec<_>>(),
896896
splits);
897897

898898
let xs: &mut [i32] = &mut [];
899899
let splits: &[&mut[i32]] = &[&mut []];
900-
assert_eq!(xs.splitn_mut(1, |x| *x == 5).collect::<Vec<_>>(),
900+
assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::<Vec<_>>(),
901901
splits);
902902
}
903903

@@ -928,18 +928,19 @@ fn test_rsplitnator() {
928928
let xs = &[1,2,3,4,5];
929929

930930
let splits: &[&[_]] = &[&[1,2,3,4,5]];
931-
assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
931+
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
932932
splits);
933933
let splits: &[&[_]] = &[&[5], &[1,2,3]];
934-
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
934+
assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
935935
splits);
936936
let splits: &[&[_]] = &[&[], &[], &[], &[1,2]];
937-
assert_eq!(xs.rsplitn(3, |_| true).collect::<Vec<_>>(),
937+
assert_eq!(xs.rsplitn(4, |_| true).collect::<Vec<_>>(),
938938
splits);
939939

940940
let xs: &[i32] = &[];
941941
let splits: &[&[i32]] = &[&[]];
942-
assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
942+
assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::<Vec<&[i32]>>(), splits);
943+
assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none());
943944
}
944945

945946
#[test]

src/libcollectionstest/str.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -885,17 +885,17 @@ fn test_char_indices_revator() {
885885
fn test_splitn_char_iterator() {
886886
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
887887

888-
let split: Vec<&str> = data.splitn(3, ' ').collect();
888+
let split: Vec<&str> = data.splitn(4, ' ').collect();
889889
assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
890890

891-
let split: Vec<&str> = data.splitn(3, |c: char| c == ' ').collect();
891+
let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect();
892892
assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]);
893893

894894
// Unicode
895-
let split: Vec<&str> = data.splitn(3, 'ä').collect();
895+
let split: Vec<&str> = data.splitn(4, 'ä').collect();
896896
assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
897897

898-
let split: Vec<&str> = data.splitn(3, |c: char| c == 'ä').collect();
898+
let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect();
899899
assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]);
900900
}
901901

@@ -928,13 +928,13 @@ fn test_rsplit() {
928928
fn test_rsplitn() {
929929
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
930930

931-
let split: Vec<&str> = data.rsplitn(1, ' ').collect();
931+
let split: Vec<&str> = data.rsplitn(2, ' ').collect();
932932
assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]);
933933

934-
let split: Vec<&str> = data.rsplitn(1, "lämb").collect();
934+
let split: Vec<&str> = data.rsplitn(2, "lämb").collect();
935935
assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]);
936936

937-
let split: Vec<&str> = data.rsplitn(1, |c: char| c == 'ä').collect();
937+
let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect();
938938
assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]);
939939
}
940940

src/libcore/slice.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1126,18 +1126,20 @@ impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> {
11261126

11271127
#[inline]
11281128
fn next(&mut self) -> Option<T> {
1129-
if self.count == 0 {
1130-
self.iter.finish()
1131-
} else {
1132-
self.count -= 1;
1133-
if self.invert { self.iter.next_back() } else { self.iter.next() }
1129+
match self.count {
1130+
0 => None,
1131+
1 => { self.count -= 1; self.iter.finish() }
1132+
_ => {
1133+
self.count -= 1;
1134+
if self.invert {self.iter.next_back()} else {self.iter.next()}
1135+
}
11341136
}
11351137
}
11361138

11371139
#[inline]
11381140
fn size_hint(&self) -> (usize, Option<usize>) {
11391141
let (lower, upper_opt) = self.iter.size_hint();
1140-
(lower, upper_opt.map(|upper| cmp::min(self.count + 1, upper)))
1142+
(lower, upper_opt.map(|upper| cmp::min(self.count, upper)))
11411143
}
11421144
}
11431145

src/libcore/str/mod.rs

+9-11
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ struct CharSplits<'a, P: Pattern<'a>> {
489489
/// splitting at most `count` times.
490490
struct CharSplitsN<'a, P: Pattern<'a>> {
491491
iter: CharSplits<'a, P>,
492-
/// The number of splits remaining
492+
/// The number of items remaining
493493
count: usize,
494494
}
495495

@@ -596,11 +596,10 @@ impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> {
596596

597597
#[inline]
598598
fn next(&mut self) -> Option<&'a str> {
599-
if self.count != 0 {
600-
self.count -= 1;
601-
self.iter.next()
602-
} else {
603-
self.iter.get_end()
599+
match self.count {
600+
0 => None,
601+
1 => { self.count = 0; self.iter.get_end() }
602+
_ => { self.count -= 1; self.iter.next() }
604603
}
605604
}
606605
}
@@ -650,11 +649,10 @@ impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P>
650649

651650
#[inline]
652651
fn next(&mut self) -> Option<&'a str> {
653-
if self.count != 0 {
654-
self.count -= 1;
655-
self.iter.next()
656-
} else {
657-
self.iter.get_remainder()
652+
match self.count {
653+
0 => None,
654+
1 => { self.count -= 1; self.iter.get_remainder() }
655+
_ => { self.count -= 1; self.iter.next() }
658656
}
659657
}
660658
}

src/libcoretest/str.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,20 @@ fn test_strslice_contains() {
6565
fn test_rsplitn_char_iterator() {
6666
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
6767

68-
let mut split: Vec<&str> = data.rsplitn(3, ' ').collect();
68+
let mut split: Vec<&str> = data.rsplitn(4, ' ').collect();
6969
split.reverse();
7070
assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
7171

72-
let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == ' ').collect();
72+
let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect();
7373
split.reverse();
7474
assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]);
7575

7676
// Unicode
77-
let mut split: Vec<&str> = data.rsplitn(3, 'ä').collect();
77+
let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect();
7878
split.reverse();
7979
assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
8080

81-
let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == 'ä').collect();
81+
let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
8282
split.reverse();
8383
assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
8484
}

src/librustc/session/config.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ macro_rules! options {
304304
{
305305
let mut op = $defaultfn();
306306
for option in matches.opt_strs($prefix) {
307-
let mut iter = option.splitn(1, '=');
307+
let mut iter = option.splitn(2, '=');
308308
let key = iter.next().unwrap();
309309
let value = iter.next();
310310
let option_to_lookup = key.replace("-", "_");
@@ -958,7 +958,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
958958
}
959959

960960
let libs = matches.opt_strs("l").into_iter().map(|s| {
961-
let mut parts = s.splitn(1, '=');
961+
let mut parts = s.splitn(2, '=');
962962
let kind = parts.next().unwrap();
963963
let (name, kind) = match (parts.next(), kind) {
964964
(None, name) |
@@ -1010,7 +1010,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10101010

10111011
let mut externs = HashMap::new();
10121012
for arg in &matches.opt_strs("extern") {
1013-
let mut parts = arg.splitn(1, '=');
1013+
let mut parts = arg.splitn(2, '=');
10141014
let name = match parts.next() {
10151015
Some(s) => s,
10161016
None => early_error("--extern value must not be empty"),

src/librustc_driver/pretty.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub enum PpMode {
7474
pub fn parse_pretty(sess: &Session,
7575
name: &str,
7676
extended: bool) -> (PpMode, Option<UserIdentifiedItem>) {
77-
let mut split = name.splitn(1, '=');
77+
let mut split = name.splitn(2, '=');
7878
let first = split.next().unwrap();
7979
let opt_second = split.next();
8080
let first = match (first, extended) {

0 commit comments

Comments
 (0)