diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 2803608567d..3e656b3e594 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4845,7 +4845,7 @@ pub fn find_best_match_for_name(@mut self, let mut smallest = 0; for maybes.eachi |i, &other| { - values[i] = str::levdistance(name, other); + values[i] = name.lev_distance(other); if values[i] <= values[smallest] { smallest = i; diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index 51fea9b46b3..d6cae1f2fa3 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -143,11 +143,9 @@ fn first_sentence_(s: &str) -> ~str { } pub fn paragraphs(s: &str) -> ~[~str] { - let mut lines = ~[]; - for str::each_line_any(s) |line| { lines.push(line.to_owned()); } let mut whitespace_lines = 0; let mut accum = ~""; - let paras = do lines.iter().fold(~[]) |paras, line| { + let paras = do s.any_line_iter().fold(~[]) |paras, line| { let mut res = paras; if line.is_whitespace() { @@ -163,9 +161,9 @@ pub fn paragraphs(s: &str) -> ~[~str] { whitespace_lines = 0; accum = if accum.is_empty() { - copy *line + line.to_owned() } else { - accum + "\n" + *line + fmt!("%s\n%s", accum, line) } } diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 17db7c24a7c..2e020cd9e5a 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -22,6 +22,7 @@ use pass::Pass; use sort_pass; +use core::iterator::IteratorUtil; use core::cell::Cell; use core::str; use core::vec; @@ -466,10 +467,7 @@ fn write_variant(ctxt: &Ctxt, doc: doc::VariantDoc) { } fn list_item_indent(item: &str) -> ~str { - let mut indented = ~[]; - for str::each_line_any(item) |line| { - indented.push(line); - } + let indented = item.any_line_iter().collect::<~[&str]>(); // separate markdown elements within `*` lists must be indented by four // spaces, or they will escape the list context. indenting everything diff --git a/src/librustdoc/sectionalize_pass.rs b/src/librustdoc/sectionalize_pass.rs index 8716f823848..c44be7f597e 100644 --- a/src/librustdoc/sectionalize_pass.rs +++ b/src/librustdoc/sectionalize_pass.rs @@ -19,7 +19,7 @@ use fold; use pass::Pass; -use core::str; +use core::iterator::IteratorUtil; pub fn mk_pass() -> Pass { Pass { @@ -104,21 +104,19 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { if desc.is_none() { return (None, ~[]); } - let mut lines = ~[]; - for str::each_line_any(*desc.get_ref()) |line| { lines.push(line.to_owned()); } let mut new_desc = None::<~str>; let mut current_section = None; let mut sections = ~[]; - for lines.each |line| { - match parse_header(copy *line) { + for desc.get_ref().any_line_iter().advance |line| { + match parse_header(line) { Some(header) => { if current_section.is_some() { - sections += [copy *current_section.get_ref()]; + sections.push(copy *current_section.get_ref()); } current_section = Some(doc::Section { - header: header, + header: header.to_owned(), body: ~"" }); } @@ -126,17 +124,17 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { match copy current_section { Some(section) => { current_section = Some(doc::Section { - body: section.body + "\n" + *line, + body: fmt!("%s\n%s", section.body, line), .. section }); } None => { new_desc = match copy new_desc { Some(desc) => { - Some(desc + "\n" + *line) + Some(fmt!("%s\n%s", desc, line)) } None => { - Some(copy *line) + Some(line.to_owned()) } }; } @@ -146,15 +144,15 @@ fn sectionalize(desc: Option<~str>) -> (Option<~str>, ~[doc::Section]) { } if current_section.is_some() { - sections += [current_section.get()]; + sections.push(current_section.unwrap()); } (new_desc, sections) } -fn parse_header(line: ~str) -> Option<~str> { +fn parse_header<'a>(line: &'a str) -> Option<&'a str> { if line.starts_with("# ") { - Some(line.slice(2u, line.len()).to_owned()) + Some(line.slice_from(2)) } else { None } diff --git a/src/librustdoc/unindent_pass.rs b/src/librustdoc/unindent_pass.rs index caf0e5376d1..2bcf04c0262 100644 --- a/src/librustdoc/unindent_pass.rs +++ b/src/librustdoc/unindent_pass.rs @@ -21,7 +21,6 @@ use core::prelude::*; -use core::str; use core::uint; use pass::Pass; use text_pass; @@ -31,8 +30,7 @@ pub fn mk_pass() -> Pass { } fn unindent(s: &str) -> ~str { - let mut lines = ~[]; - for str::each_line_any(s) |line| { lines.push(line.to_owned()); } + let lines = s.any_line_iter().collect::<~[&str]>(); let mut saw_first_line = false; let mut saw_second_line = false; let min_indent = do lines.iter().fold(uint::max_value) @@ -76,19 +74,20 @@ fn unindent(s: &str) -> ~str { } }; - if !lines.is_empty() { - let unindented = ~[lines.head().trim().to_owned()] - + do lines.tail().map |line| { - if line.is_whitespace() { - copy *line - } else { - assert!(line.len() >= min_indent); - line.slice(min_indent, line.len()).to_owned() - } - }; - unindented.connect("\n") - } else { - s.to_str() + match lines { + [head, .. tail] => { + let mut unindented = ~[ head.trim() ]; + unindented.push_all(do tail.map |&line| { + if line.is_whitespace() { + line + } else { + assert!(line.len() >= min_indent); + line.slice_from(min_indent) + } + }); + unindented.connect("\n") + } + [] => s.to_owned() } } diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 1086fcaa75c..fbdbb1b3f74 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -26,7 +26,7 @@ use cmp::{TotalOrd, Ordering, Less, Equal, Greater}; use container::Container; use iter::Times; -use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator}; +use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator, MapIterator}; use libc; use option::{None, Option, Some}; use old_iter::{BaseIter, EqIter}; @@ -291,6 +291,10 @@ pub struct StrCharSplitIterator<'self,Sep> { FilterIterator<'self, &'self str, StrCharSplitIterator<'self, extern "Rust" fn(char) -> bool>>; +/// An iterator over the lines of a string, separated by either `\n` or (`\r\n`). +pub type AnyLineIterator<'self> = + MapIterator<'self, &'self str, &'self str, StrCharSplitIterator<'self, char>>; + impl<'self, Sep: CharEq> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> { #[inline] fn next(&mut self) -> Option<&'self str> { @@ -400,56 +404,6 @@ fn next(&mut self) -> Option<&'self str> { } } -/// Levenshtein Distance between two strings -pub fn levdistance(s: &str, t: &str) -> uint { - - let slen = s.len(); - let tlen = t.len(); - - if slen == 0 { return tlen; } - if tlen == 0 { return slen; } - - let mut dcol = vec::from_fn(tlen + 1, |x| x); - - for s.iter().enumerate().advance |(i, sc)| { - - let mut current = i; - dcol[0] = current + 1; - - for t.iter().enumerate().advance |(j, tc)| { - - let next = dcol[j + 1]; - - if sc == tc { - dcol[j + 1] = current; - } else { - dcol[j + 1] = ::cmp::min(current, next); - dcol[j + 1] = ::cmp::min(dcol[j + 1], dcol[j]) + 1; - } - - current = next; - } - } - - return dcol[tlen]; -} - -/** - * Splits a string into substrings separated by LF ('\n') - * and/or CR LF ("\r\n") - */ -pub fn each_line_any<'a>(s: &'a str, it: &fn(&'a str) -> bool) -> bool { - for s.line_iter().advance |s| { - let l = s.len(); - if l > 0u && s[l - 1u] == '\r' as u8 { - if !it( unsafe { raw::slice_bytes(s, 0, l - 1) } ) { return false; } - } else { - if !it( s ) { return false; } - } - } - return true; -} - /** Splits a string into substrings with possibly internal whitespace, * each of them at most `lim` bytes long. The substrings have leading and trailing * whitespace removed, and are only cut at whitespace boundaries. @@ -751,21 +705,6 @@ impl<'self, S: Str> Equiv for ~str { fn equiv(&self, other: &S) -> bool { eq_slice(*self, other.as_slice()) } } - -/* -Section: Iterating through strings -*/ - -/// Apply a function to each character -pub fn map(ss: &str, ff: &fn(char) -> char) -> ~str { - let mut result = ~""; - result.reserve(ss.len()); - for ss.iter().advance |cc| { - result.push_char(ff(cc)); - } - result -} - /* Section: Searching */ @@ -989,40 +928,6 @@ pub fn as_buf(s: &str, f: &fn(*u8, uint) -> T) -> T { } } -/** - * Returns the byte offset of an inner slice relative to an enclosing outer slice - * - * # Example - * - * ~~~ {.rust} - * let string = "a\nb\nc"; - * let mut lines = ~[]; - * for string.line_iter().advance |line| { lines.push(line) } - * - * assert!(subslice_offset(string, lines[0]) == 0); // &"a" - * assert!(subslice_offset(string, lines[1]) == 2); // &"b" - * assert!(subslice_offset(string, lines[2]) == 4); // &"c" - * ~~~ - */ -#[inline(always)] -pub fn subslice_offset(outer: &str, inner: &str) -> uint { - do as_buf(outer) |a, a_len| { - do as_buf(inner) |b, b_len| { - let a_start: uint; - let a_end: uint; - let b_start: uint; - let b_end: uint; - unsafe { - a_start = cast::transmute(a); a_end = a_len + cast::transmute(a); - b_start = cast::transmute(b); b_end = b_len + cast::transmute(b); - } - assert!(a_start <= b_start); - assert!(b_end <= a_end); - b_start - a_start - } - } -} - /// Unsafe operations pub mod raw { use cast; @@ -1256,6 +1161,7 @@ fn split_options_iter(&self, sep: Sep, count: uint, allow_trailing_ fn matches_index_iter(&self, sep: &'self str) -> StrMatchesIndexIterator<'self>; fn split_str_iter(&self, &'self str) -> StrStrSplitIterator<'self>; fn line_iter(&self) -> StrCharSplitIterator<'self, char>; + fn any_line_iter(&self) -> AnyLineIterator<'self>; fn word_iter(&self) -> WordIterator<'self>; fn ends_with(&self, needle: &str) -> bool; fn is_empty(&self) -> bool; @@ -1296,6 +1202,12 @@ fn split_options_iter(&self, sep: Sep, count: uint, allow_trailing_ fn repeat(&self, nn: uint) -> ~str; fn slice_shift_char(&self) -> (char, &'self str); + + fn map_chars(&self, ff: &fn(char) -> char) -> ~str; + + fn lev_distance(&self, t: &str) -> uint; + + fn subslice_offset(&self, inner: &str) -> uint; } /// Extension methods for strings @@ -1437,6 +1349,17 @@ fn split_str_iter(&self, sep: &'self str) -> StrStrSplitIterator<'self> { fn line_iter(&self) -> StrCharSplitIterator<'self, char> { self.split_options_iter('\n', self.len(), false) } + + /// An iterator over the lines of a string, separated by either + /// `\n` or (`\r\n`). + fn any_line_iter(&self) -> AnyLineIterator<'self> { + do self.line_iter().transform |line| { + let l = line.len(); + if l > 0 && line[l - 1] == '\r' as u8 { line.slice(0, l - 1) } + else { line } + } + } + /// An iterator over the words of a string (subsequences separated /// by any sequence of whitespace). #[inline] @@ -1921,6 +1844,85 @@ fn slice_shift_char(&self) -> (char, &'self str) { } + /// Apply a function to each character. + fn map_chars(&self, ff: &fn(char) -> char) -> ~str { + let mut result = with_capacity(self.len()); + for self.iter().advance |cc| { + result.push_char(ff(cc)); + } + result + } + + /// Levenshtein Distance between two strings. + fn lev_distance(&self, t: &str) -> uint { + let slen = self.len(); + let tlen = t.len(); + + if slen == 0 { return tlen; } + if tlen == 0 { return slen; } + + let mut dcol = vec::from_fn(tlen + 1, |x| x); + + for self.iter().enumerate().advance |(i, sc)| { + + let mut current = i; + dcol[0] = current + 1; + + for t.iter().enumerate().advance |(j, tc)| { + + let next = dcol[j + 1]; + + if sc == tc { + dcol[j + 1] = current; + } else { + dcol[j + 1] = ::cmp::min(current, next); + dcol[j + 1] = ::cmp::min(dcol[j + 1], dcol[j]) + 1; + } + + current = next; + } + } + + return dcol[tlen]; + } + + + /** + * Returns the byte offset of an inner slice relative to an enclosing outer slice. + * + * Fails if `inner` is not a direct slice contained within self. + * + * # Example + * + * ~~~ {.rust} + * let string = "a\nb\nc"; + * let mut lines = ~[]; + * for string.line_iter().advance |line| { lines.push(line) } + * + * assert!(string.subslice_offset(lines[0]) == 0); // &"a" + * assert!(string.subslice_offset(lines[1]) == 2); // &"b" + * assert!(string.subslice_offset(lines[2]) == 4); // &"c" + * ~~~ + */ + #[inline(always)] + fn subslice_offset(&self, inner: &str) -> uint { + do as_buf(*self) |a, a_len| { + do as_buf(inner) |b, b_len| { + let a_start: uint; + let a_end: uint; + let b_start: uint; + let b_end: uint; + unsafe { + a_start = cast::transmute(a); a_end = a_len + cast::transmute(a); + b_start = cast::transmute(b); b_end = b_len + cast::transmute(b); + } + assert!(a_start <= b_start); + assert!(b_end <= a_end); + b_start - a_start + } + } + } + } #[allow(missing_doc)] @@ -3003,15 +3005,15 @@ fn test_subslice_offset() { let a = "kernelsprite"; let b = a.slice(7, a.len()); let c = a.slice(0, a.len() - 6); - assert_eq!(subslice_offset(a, b), 7); - assert_eq!(subslice_offset(a, c), 0); + assert_eq!(a.subslice_offset(b), 7); + assert_eq!(a.subslice_offset(c), 0); let string = "a\nb\nc"; let mut lines = ~[]; for string.line_iter().advance |line| { lines.push(line) } - assert_eq!(subslice_offset(string, lines[0]), 0); - assert_eq!(subslice_offset(string, lines[1]), 2); - assert_eq!(subslice_offset(string, lines[2]), 4); + assert_eq!(string.subslice_offset(lines[0]), 0); + assert_eq!(string.subslice_offset(lines[1]), 2); + assert_eq!(string.subslice_offset(lines[2]), 4); } #[test] @@ -3019,7 +3021,7 @@ fn test_subslice_offset() { fn test_subslice_offset_2() { let a = "alchemiter"; let b = "cruxtruder"; - subslice_offset(a, b); + a.subslice_offset(b); } #[test] @@ -3069,8 +3071,8 @@ fn test_contains_char() { #[test] fn test_map() { - assert_eq!(~"", map("", |c| unsafe {libc::toupper(c as c_char)} as char)); - assert_eq!(~"YMCA", map("ymca", |c| unsafe {libc::toupper(c as c_char)} as char)); + assert_eq!(~"", "".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char)); + assert_eq!(~"YMCA", "ymca".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char)); } #[test] diff --git a/src/libsyntax/parse/comments.rs b/src/libsyntax/parse/comments.rs index 68473f11537..82a7b55eeee 100644 --- a/src/libsyntax/parse/comments.rs +++ b/src/libsyntax/parse/comments.rs @@ -89,12 +89,11 @@ fn block_trim(lines: ~[~str], chars: ~str, max: Option) -> ~[~str] { } return do lines.map |line| { - let mut chars = ~[]; - for line.iter().advance |c| { chars.push(c) } + let chars = line.iter().collect::<~[char]>(); if i > chars.len() { ~"" } else { - str::from_chars(chars.slice(i, chars.len()).to_owned()) + str::from_chars(chars.slice(i, chars.len())) } }; } @@ -103,14 +102,13 @@ fn block_trim(lines: ~[~str], chars: ~str, max: Option) -> ~[~str] { // FIXME #5475: // return comment.slice(3u, comment.len()).trim().to_owned(); let r = comment.slice(3u, comment.len()); return r.trim().to_owned(); - } if comment.starts_with("/*") { - let mut lines = ~[]; - for str::each_line_any(comment.slice(3u, comment.len() - 2u)) |line| { - lines.push(line.to_owned()) - } + let lines = comment.slice(3u, comment.len() - 2u) + .any_line_iter() + .transform(|s| s.to_owned()) + .collect::<~[~str]>(); let lines = vertical_trim(lines); let lines = block_trim(lines, ~"\t ", None); let lines = block_trim(lines, ~"*", Some(1u));