about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-06-14 01:39:06 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-06-16 10:50:28 +1000
commit4b18fff2be74df9a2db5ee6ab418da322ad6ae18 (patch)
tree80a7b5caf2c7b2d1f6dc455fb725f4138f008f57
parentc989b79127c5062df0a64d8c383de93c82a3d9b7 (diff)
downloadrust-4b18fff2be74df9a2db5ee6ab418da322ad6ae18.tar.gz
rust-4b18fff2be74df9a2db5ee6ab418da322ad6ae18.zip
std: convert str::{map,levdistance,subslice_offset} to methods.
The first two become map_chars and lev_distance. Also, remove a few
allocations in rustdoc.
-rw-r--r--src/librustc/middle/resolve.rs2
-rw-r--r--src/librustdoc/desc_to_brief_pass.rs8
-rw-r--r--src/librustdoc/markdown_pass.rs6
-rw-r--r--src/librustdoc/sectionalize_pass.rs24
-rw-r--r--src/librustdoc/unindent_pass.rs31
-rw-r--r--src/libstd/str.rs218
-rw-r--r--src/libsyntax/parse/comments.rs14
7 files changed, 148 insertions, 155 deletions
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 @@ impl Resolver {
         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 markdown_writer::WriterFactory;
 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::Fold;
 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 @@ middle of a line, and each of the following lines is indented.
 
 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 clone::Clone;
 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 type WordIterator<'self> =
     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 @@ impl<'self> Iterator<&'self str> for StrStrSplitIterator<'self> {
     }
 }
 
-/// 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<S> 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<T>(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 @@ pub trait StrSlice<'self> {
     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 @@ pub trait StrSlice<'self> {
     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 @@ impl<'self> StrSlice<'self> for &'self str {
     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 @@ impl<'self> StrSlice<'self> for &'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 @@ mod tests {
         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 @@ mod tests {
     fn test_subslice_offset_2() {
         let a = "alchemiter";
         let b = "cruxtruder";
-        subslice_offset(a, b);
+        a.subslice_offset(b);
     }
 
     #[test]
@@ -3069,8 +3071,8 @@ mod tests {
 
     #[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 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~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 @@ pub fn strip_doc_comment_decoration(comment: &str) -> ~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));