Skip to content

Commit

Permalink
std: Changing the meaning of the count to splitn
Browse files Browse the repository at this point in the history
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]
  • Loading branch information
alexcrichton committed Apr 1, 2015
1 parent d528aa9 commit e98dce3
Show file tree
Hide file tree
Showing 14 changed files with 85 additions and 66 deletions.
2 changes: 1 addition & 1 deletion src/compiletest/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
parse_name_value_directive(line, "exec-env").map(|nv| {
// nv is either FOO or FOO=BAR
let mut strs: Vec<String> = nv
.splitn(1, '=')
.splitn(2, '=')
.map(|s| s.to_string())
.collect();

Expand Down
24 changes: 18 additions & 6 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,17 +328,20 @@ impl<T> [T] {
}

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

/// Returns an iterator over subslices separated by elements that match
/// `pred` limited to splitting at most `n` times. This starts at the end of
/// `pred` limited to returning at most `n` items. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
///
/// The last element returned, if any, will contain the remainder of the
/// slice.
///
/// # Examples
///
/// Print the slice split once, starting from the end, by numbers divisible
/// by 3 (i.e. `[50]`, `[10, 40, 30, 20]`):
///
/// ```
/// let v = [10, 40, 30, 20, 60, 50];
/// for group in v.rsplitn(1, |num| *num % 3 == 0) {
/// for group in v.rsplitn(2, |num| *num % 3 == 0) {
/// println!("{:?}", group);
/// }
/// ```
Expand Down Expand Up @@ -626,8 +632,11 @@ impl<T> [T] {
}

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

/// Returns an iterator over subslices separated by elements that match
/// `pred` limited to splitting at most `n` times. This starts at the end of
/// `pred` limited to returning at most `n` items. This starts at the end of
/// the slice and works backwards. The matched element is not contained in
/// the subslices.
///
/// The last element returned, if any, will contain the remainder of the
/// slice.
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rsplitn_mut<F>(&mut self, n: usize, pred: F) -> RSplitNMut<T, F>
Expand Down
28 changes: 17 additions & 11 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -610,24 +610,27 @@ impl str {
core_str::StrExt::split(&self[..], pat)
}

/// An iterator over substrings of `self`, separated by characters matched by a pattern,
/// restricted to splitting at most `count` times.
/// An iterator over substrings of `self`, separated by characters matched
/// by a pattern, returning most `count` items.
///
/// The pattern can be a simple `&str`, or a closure that determines
/// the split.
///
/// The last element returned, if any, will contain the remainder of the
/// string.
///
/// # Examples
///
/// Simple `&str` patterns:
///
/// ```
/// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect();
/// assert_eq!(v, ["Mary", "had", "a little lambda"]);
/// assert_eq!(v, ["Mary", "had a little lambda"]);
///
/// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect();
/// assert_eq!(v, ["lion", "", "tigerXleopard"]);
/// assert_eq!(v, ["lion", "XtigerXleopard"]);
///
/// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect();
/// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect();
/// assert_eq!(v, ["abcXdef"]);
///
/// let v: Vec<&str> = "".splitn(1, 'X').collect();
Expand All @@ -637,7 +640,7 @@ impl str {
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect();
/// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect();
/// assert_eq!(v, ["abc", "def2ghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down Expand Up @@ -705,25 +708,28 @@ impl str {
}

/// An iterator over substrings of `self`, separated by a pattern,
/// starting from the end of the string, restricted to splitting
/// at most `count` times.
/// starting from the end of the string, restricted to returning
/// at most `count` items.
///
/// The last element returned, if any, will contain the remainder of the
/// string.
///
/// # Examples
///
/// Simple patterns:
///
/// ```
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect();
/// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect();
/// assert_eq!(v, ["lamb", "little", "Mary had a"]);
///
/// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect();
/// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect();
/// assert_eq!(v, ["leopard", "lion::tiger"]);
/// ```
///
/// More complex patterns with a lambda:
///
/// ```
/// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect();
/// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect();
/// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
25 changes: 13 additions & 12 deletions src/libcollectionstest/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,37 +867,37 @@ fn test_splitnator() {
let xs = &[1,2,3,4,5];

let splits: &[&[_]] = &[&[1,2,3,4,5]];
assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[1], &[3,4,5]];
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[], &[], &[], &[4,5]];
assert_eq!(xs.splitn(3, |_| true).collect::<Vec<_>>(),
assert_eq!(xs.splitn(4, |_| true).collect::<Vec<_>>(),
splits);

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

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

let splits: &[&mut[_]] = &[&mut [1,2,3,4,5]];
assert_eq!(xs.splitn_mut(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&mut[_]] = &[&mut [1], &mut [3,4,5]];
assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&mut[_]] = &[&mut [], &mut [], &mut [], &mut [4,5]];
assert_eq!(xs.splitn_mut(3, |_| true).collect::<Vec<_>>(),
assert_eq!(xs.splitn_mut(4, |_| true).collect::<Vec<_>>(),
splits);

let xs: &mut [i32] = &mut [];
let splits: &[&mut[i32]] = &[&mut []];
assert_eq!(xs.splitn_mut(1, |x| *x == 5).collect::<Vec<_>>(),
assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::<Vec<_>>(),
splits);
}

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

let splits: &[&[_]] = &[&[1,2,3,4,5]];
assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[5], &[1,2,3]];
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<_>>(),
assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::<Vec<_>>(),
splits);
let splits: &[&[_]] = &[&[], &[], &[], &[1,2]];
assert_eq!(xs.rsplitn(3, |_| true).collect::<Vec<_>>(),
assert_eq!(xs.rsplitn(4, |_| true).collect::<Vec<_>>(),
splits);

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

#[test]
Expand Down
14 changes: 7 additions & 7 deletions src/libcollectionstest/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,17 +885,17 @@ fn test_char_indices_revator() {
fn test_splitn_char_iterator() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";

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

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

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

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

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

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

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

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

Expand Down
14 changes: 8 additions & 6 deletions src/libcore/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1126,18 +1126,20 @@ impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> {

#[inline]
fn next(&mut self) -> Option<T> {
if self.count == 0 {
self.iter.finish()
} else {
self.count -= 1;
if self.invert { self.iter.next_back() } else { self.iter.next() }
match self.count {
0 => None,
1 => { self.count -= 1; self.iter.finish() }
_ => {
self.count -= 1;
if self.invert {self.iter.next_back()} else {self.iter.next()}
}
}
}

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

Expand Down
20 changes: 9 additions & 11 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ struct CharSplits<'a, P: Pattern<'a>> {
/// splitting at most `count` times.
struct CharSplitsN<'a, P: Pattern<'a>> {
iter: CharSplits<'a, P>,
/// The number of splits remaining
/// The number of items remaining
count: usize,
}

Expand Down Expand Up @@ -612,11 +612,10 @@ impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> {

#[inline]
fn next(&mut self) -> Option<&'a str> {
if self.count != 0 {
self.count -= 1;
self.iter.next()
} else {
self.iter.get_end()
match self.count {
0 => None,
1 => { self.count = 0; self.iter.get_end() }
_ => { self.count -= 1; self.iter.next() }
}
}
}
Expand Down Expand Up @@ -666,11 +665,10 @@ impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P>

#[inline]
fn next(&mut self) -> Option<&'a str> {
if self.count != 0 {
self.count -= 1;
self.iter.next()
} else {
self.iter.get_remainder()
match self.count {
0 => None,
1 => { self.count -= 1; self.iter.get_remainder() }
_ => { self.count -= 1; self.iter.next() }
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/libcoretest/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,20 @@ fn test_strslice_contains() {
fn test_rsplitn_char_iterator() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";

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

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

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

let mut split: Vec<&str> = data.rsplitn(3, |c: char| c == 'ä').collect();
let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect();
split.reverse();
assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]);
}
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ macro_rules! options {
{
let mut op = $defaultfn();
for option in matches.opt_strs($prefix) {
let mut iter = option.splitn(1, '=');
let mut iter = option.splitn(2, '=');
let key = iter.next().unwrap();
let value = iter.next();
let option_to_lookup = key.replace("-", "_");
Expand Down Expand Up @@ -958,7 +958,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
}

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

let mut externs = HashMap::new();
for arg in &matches.opt_strs("extern") {
let mut parts = arg.splitn(1, '=');
let mut parts = arg.splitn(2, '=');
let name = match parts.next() {
Some(s) => s,
None => early_error("--extern value must not be empty"),
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ pub enum PpMode {
pub fn parse_pretty(sess: &Session,
name: &str,
extended: bool) -> (PpMode, Option<UserIdentifiedItem>) {
let mut split = name.splitn(1, '=');
let mut split = name.splitn(2, '=');
let first = split.next().unwrap();
let opt_second = split.next();
let first = match (first, extended) {
Expand Down
Loading

0 comments on commit e98dce3

Please sign in to comment.