From 0cfc08d81e7cc664330ce9d38a874c14a4ae51bf Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 10 Jun 2013 13:09:51 +1000 Subject: [PATCH] std: convert character-based str::find_* to methods. Add .slice_{to,from} methods. --- src/compiletest/runtest.rs | 2 +- src/libfuzzer/fuzzer.rc | 2 +- src/librustc/middle/lint.rs | 17 +- src/librustc/middle/resolve.rs | 2 +- src/librustdoc/desc_to_brief_pass.rs | 14 +- src/librustpkg/version.rs | 2 +- src/libstd/path.rs | 16 +- src/libstd/str.rs | 497 ++++++++------------------- src/libsyntax/codemap.rs | 11 +- 9 files changed, 158 insertions(+), 405 deletions(-) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 6812f6e4455..8f493fa2d06 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -417,7 +417,7 @@ fn scan_until_char(haystack: &str, needle: char, idx: &mut uint) -> bool { if *idx >= haystack.len() { return false; } - let opt = str::find_char_from(haystack, needle, *idx); + let opt = haystack.slice_from(*idx).find(needle); if opt.is_none() { return false; } diff --git a/src/libfuzzer/fuzzer.rc b/src/libfuzzer/fuzzer.rc index bd72f0891dd..95aea33d31a 100644 --- a/src/libfuzzer/fuzzer.rc +++ b/src/libfuzzer/fuzzer.rc @@ -375,7 +375,7 @@ pub fn check_variants_T(crate: @ast::crate, } pub fn last_part(filename: ~str) -> ~str { - let ix = str::rfind_char(filename, '/').get(); + let ix = filename.rfind('/').get(); filename.slice(ix + 1u, filename.len() - 3u).to_owned() } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 74e001f4e13..7462067162d 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -841,26 +841,11 @@ fn check_item_non_camel_case_types(cx: &Context, it: @ast::item) { fn is_camel_case(cx: ty::ctxt, ident: ast::ident) -> bool { let ident = cx.sess.str_of(ident); assert!(!ident.is_empty()); - let ident = ident_without_trailing_underscores(*ident); - let ident = ident_without_leading_underscores(ident); + let ident = ident.trim_chars(&['_']); char::is_uppercase(str::char_at(ident, 0)) && !ident.contains_char('_') } - fn ident_without_trailing_underscores<'r>(ident: &'r str) -> &'r str { - match str::rfind(ident, |c| c != '_') { - Some(idx) => ident.slice(0, idx + 1), - None => ident, // all underscores - } - } - - fn ident_without_leading_underscores<'r>(ident: &'r str) -> &'r str { - match str::find(ident, |c| c != '_') { - Some(idx) => ident.slice(idx, ident.len()), - None => ident // all underscores - } - } - fn check_case(cx: &Context, ident: ast::ident, span: span) { if !is_camel_case(cx.tcx, ident) { cx.span_lint(non_camel_case_types, span, diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index ffa3c815b28..dd70c2bfb56 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -2681,7 +2681,7 @@ impl Resolver { match module_prefix_result { Failed => { let mpath = self.idents_to_str(module_path); - match str::rfind(self.idents_to_str(module_path), |c| { c == ':' }) { + match self.idents_to_str(module_path).rfind(':') { Some(idx) => { self.session.span_err(span, fmt!("unresolved import: could not find `%s` \ in `%s`", str::substr(mpath, idx, diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index f66012696ae..0f4ade0551d 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -118,19 +118,17 @@ fn first_sentence_(s: &str) -> ~str { let mut dotcount = 0; // The index of the character following a single dot. This allows // Things like [0..1) to appear in the brief description - let idx = do str::find(s) |ch| { + let idx = s.find(|ch: char| { if ch == '.' { dotcount += 1; false + } else if dotcount == 1 { + true } else { - if dotcount == 1 { - true - } else { - dotcount = 0; - false - } + dotcount = 0; + false } - }; + }); match idx { Some(idx) if idx > 2u => { str::to_owned(s.slice(0, idx - 1)) diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs index c966ede3cdf..b38f440a941 100644 --- a/src/librustpkg/version.rs +++ b/src/librustpkg/version.rs @@ -175,7 +175,7 @@ pub fn split_version<'a>(s: &'a str) -> Option<(&'a str, Version)> { if { let mut i: uint = 0; for str::to_chars(s).each |&c| { if c == '#' { i += 1; } }; i > 1 } { return None; } - match str::rfind_char(s, '#') { + match s.rfind('#') { Some(i) => { debug!("in %s, i = %?", s, i); let path = s.slice(0, i); diff --git a/src/libstd/path.rs b/src/libstd/path.rs index eb78120c6be..4df07830b23 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -479,8 +479,8 @@ impl GenericPath for PosixPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) => Some(f.slice(0, p).to_owned()), + match f.rfind('.') { + Some(p) => Some(f.slice_to(p).to_owned()), None => Some(copy *f), } } @@ -491,8 +491,8 @@ impl GenericPath for PosixPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) if p < f.len() => Some(f.slice(p, f.len()).to_owned()), + match f.rfind('.') { + Some(p) if p < f.len() => Some(f.slice_from(p).to_owned()), _ => None, } } @@ -693,8 +693,8 @@ impl GenericPath for WindowsPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) => Some(f.slice(0, p).to_owned()), + match f.rfind('.') { + Some(p) => Some(f.slice_to(p).to_owned()), None => Some(copy *f), } } @@ -705,8 +705,8 @@ impl GenericPath for WindowsPath { match self.filename() { None => None, Some(ref f) => { - match str::rfind_char(*f, '.') { - Some(p) if p < f.len() => Some(f.slice(p, f.len()).to_owned()), + match f.rfind('.') { + Some(p) if p < f.len() => Some(f.slice_from(p).to_owned()), _ => None, } } diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 46bf0b08c10..a7f152a27e5 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -21,6 +21,7 @@ use at_vec; use cast::transmute; use cast; use char; +use char::Char; use clone::Clone; use cmp::{TotalOrd, Ordering, Less, Equal, Greater}; use container::Container; @@ -510,7 +511,7 @@ pub fn unshift_char(s: &mut ~str, ch: char) { pub fn trim_left_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { if chars_to_trim.is_empty() { return s; } - match find(s, |c| !chars_to_trim.contains(&c)) { + match s.find(|c| !chars_to_trim.contains(&c)) { None => "", Some(first) => unsafe { raw::slice_bytes(s, first, s.len()) } } @@ -528,7 +529,7 @@ pub fn trim_left_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { pub fn trim_right_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { if chars_to_trim.is_empty() { return s; } - match rfind(s, |c| !chars_to_trim.contains(&c)) { + match s.rfind(|c| !chars_to_trim.contains(&c)) { None => "", Some(last) => { let next = char_range_at(s, last).next; @@ -552,7 +553,7 @@ pub fn trim_chars<'a>(s: &'a str, chars_to_trim: &[char]) -> &'a str { /// Returns a string with leading whitespace removed pub fn trim_left<'a>(s: &'a str) -> &'a str { - match find(s, |c| !char::is_whitespace(c)) { + match s.find(|c| !char::is_whitespace(c)) { None => "", Some(first) => unsafe { raw::slice_bytes(s, first, s.len()) } } @@ -560,7 +561,7 @@ pub fn trim_left<'a>(s: &'a str) -> &'a str { /// Returns a string with trailing whitespace removed pub fn trim_right<'a>(s: &'a str) -> &'a str { - match rfind(s, |c| !char::is_whitespace(c)) { + match s.rfind(|c| !char::is_whitespace(c)) { None => "", Some(last) => { let next = char_range_at(s, last).next; @@ -621,6 +622,34 @@ pub fn substr<'a>(s: &'a str, begin: uint, n: uint) -> &'a str { s.slice(begin, begin + count_bytes(s, begin, n)) } +/// Something that can be used to compare against a character +pub trait CharEq { + /// Determine if the splitter should split at the given character + fn matches(&self, char) -> bool; + /// Indicate if this is only concerned about ASCII characters, + /// which can allow for a faster implementation. + fn only_ascii(&self) -> bool; +} +impl CharEq for char { + #[inline(always)] + fn matches(&self, c: char) -> bool { *self == c } + + fn only_ascii(&self) -> bool { (*self as uint) < 128 } +} +impl<'self> CharEq for &'self fn(char) -> bool { + #[inline(always)] + fn matches(&self, c: char) -> bool { (*self)(c) } + + fn only_ascii(&self) -> bool { false } +} +impl CharEq for extern "Rust" fn(char) -> bool { + #[inline(always)] + fn matches(&self, c: char) -> bool { (*self)(c) } + + fn only_ascii(&self) -> bool { false } +} + + /// An iterator over the substrings of a string, separated by `sep`. pub struct StrCharSplitIterator<'self,Sep> { priv string: &'self str, @@ -639,34 +668,7 @@ pub type WordIterator<'self> = FilterIterator<'self, &'self str, StrCharSplitIterator<'self, extern "Rust" fn(char) -> bool>>; -/// A separator for splitting a string character-wise -pub trait StrCharSplitSeparator { - /// Determine if the splitter should split at the given character - fn should_split(&self, char) -> bool; - /// Indicate if the splitter only uses ASCII characters, which - /// allows for a faster implementation. - fn only_ascii(&self) -> bool; -} -impl StrCharSplitSeparator for char { - #[inline(always)] - fn should_split(&self, c: char) -> bool { *self == c } - - fn only_ascii(&self) -> bool { (*self as uint) < 128 } -} -impl<'self> StrCharSplitSeparator for &'self fn(char) -> bool { - #[inline(always)] - fn should_split(&self, c: char) -> bool { (*self)(c) } - - fn only_ascii(&self) -> bool { false } -} -impl<'self> StrCharSplitSeparator for extern "Rust" fn(char) -> bool { - #[inline(always)] - fn should_split(&self, c: char) -> bool { (*self)(c) } - - fn only_ascii(&self) -> bool { false } -} - -impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> { +impl<'self, Sep: CharEq> Iterator<&'self str> for StrCharSplitIterator<'self, Sep> { #[inline] fn next(&mut self) -> Option<&'self str> { if self.finished { return None } @@ -680,7 +682,7 @@ impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIte while self.position < l && self.count > 0 { let byte = self.string[self.position]; - if self.sep.should_split(byte as char) { + if self.sep.matches(byte as char) { let slice = unsafe { raw::slice_bytes(self.string, start, self.position) }; self.position += 1; self.count -= 1; @@ -692,7 +694,7 @@ impl<'self, Sep: StrCharSplitSeparator> Iterator<&'self str> for StrCharSplitIte while self.position < l && self.count > 0 { let CharRange {ch, next} = char_range_at(self.string, self.position); - if self.sep.should_split(ch) { + if self.sep.matches(ch) { let slice = unsafe { raw::slice_bytes(self.string, start, self.position) }; self.position = next; self.count -= 1; @@ -1157,318 +1159,6 @@ pub fn map(ss: &str, ff: &fn(char) -> char) -> ~str { Section: Searching */ -/** - * Returns the byte index of the first matching character - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - */ -pub fn find_char(s: &str, c: char) -> Option { - find_char_between(s, c, 0u, s.len()) -} - -/** - * Returns the byte index of the first matching character beginning - * from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, inclusive - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `s.len()`. `start` must be the - * index of a character boundary, as defined by `is_char_boundary`. - */ -pub fn find_char_from(s: &str, c: char, start: uint) -> Option { - find_char_between(s, c, start, s.len()) -} - -/** - * Returns the byte index of the first matching character within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, inclusive - * * `end` - The byte index to end searching at, exclusive - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `end` and `end` must be less than - * or equal to `s.len()`. `start` must be the index of a character boundary, - * as defined by `is_char_boundary`. - */ -pub fn find_char_between(s: &str, c: char, start: uint, end: uint) - -> Option { - if c < 128u as char { - assert!(start <= end); - assert!(end <= s.len()); - let mut i = start; - let b = c as u8; - while i < end { - if s[i] == b { return Some(i); } - i += 1u; - } - return None; - } else { - find_between(s, start, end, |x| x == c) - } -} - -/** - * Returns the byte index of the last matching character - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - */ -pub fn rfind_char(s: &str, c: char) -> Option { - rfind_char_between(s, c, s.len(), 0u) -} - -/** - * Returns the byte index of the last matching character beginning - * from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, exclusive - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `s.len()`. `start` must be - * the index of a character boundary, as defined by `is_char_boundary`. - */ -pub fn rfind_char_from(s: &str, c: char, start: uint) -> Option { - rfind_char_between(s, c, start, 0u) -} - -/** - * Returns the byte index of the last matching character within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `c` - The character to search for - * * `start` - The byte index to begin searching at, exclusive - * * `end` - The byte index to end searching at, inclusive - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `end` must be less than or equal to `start` and `start` must be less than - * or equal to `s.len()`. `start` must be the index of a character boundary, - * as defined by `is_char_boundary`. - */ -pub fn rfind_char_between(s: &str, c: char, start: uint, end: uint) -> Option { - if c < 128u as char { - assert!(start >= end); - assert!(start <= s.len()); - let mut i = start; - let b = c as u8; - while i > end { - i -= 1u; - if s[i] == b { return Some(i); } - } - return None; - } else { - rfind_between(s, start, end, |x| x == c) - } -} - -/** - * Returns the byte index of the first character that satisfies - * the given predicate - * - * # Arguments - * - * * `s` - The string to search - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - */ -pub fn find(s: &str, f: &fn(char) -> bool) -> Option { - find_between(s, 0u, s.len(), f) -} - -/** - * Returns the byte index of the first character that satisfies - * the given predicate, beginning from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, inclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the first matching charactor - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `s.len()`. `start` must be the - * index of a character boundary, as defined by `is_char_boundary`. - */ -pub fn find_from(s: &str, start: uint, f: &fn(char) - -> bool) -> Option { - find_between(s, start, s.len(), f) -} - -/** - * Returns the byte index of the first character that satisfies - * the given predicate, within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, inclusive - * * `end` - The byte index to end searching at, exclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the first matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `end` and `end` must be less than - * or equal to `s.len()`. `start` must be the index of a character - * boundary, as defined by `is_char_boundary`. - */ -pub fn find_between(s: &str, start: uint, end: uint, f: &fn(char) -> bool) -> Option { - assert!(start <= end); - assert!(end <= s.len()); - assert!(is_char_boundary(s, start)); - let mut i = start; - while i < end { - let CharRange {ch, next} = char_range_at(s, i); - if f(ch) { return Some(i); } - i = next; - } - return None; -} - -/** - * Returns the byte index of the last character that satisfies - * the given predicate - * - * # Arguments - * - * * `s` - The string to search - * * `f` - The predicate to satisfy - * - * # Return value - * - * An option containing the byte index of the last matching character - * or `none` if there is no match - */ -pub fn rfind(s: &str, f: &fn(char) -> bool) -> Option { - rfind_between(s, s.len(), 0u, f) -} - -/** - * Returns the byte index of the last character that satisfies - * the given predicate, beginning from a given byte offset - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, exclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `start` must be less than or equal to `s.len()', `start` must be the - * index of a character boundary, as defined by `is_char_boundary` - */ -pub fn rfind_from(s: &str, start: uint, f: &fn(char) -> bool) -> Option { - rfind_between(s, start, 0u, f) -} - -/** - * Returns the byte index of the last character that satisfies - * the given predicate, within a given range - * - * # Arguments - * - * * `s` - The string to search - * * `start` - The byte index to begin searching at, exclusive - * * `end` - The byte index to end searching at, inclusive - * * `f` - The predicate to satisfy - * - * # Return value - * - * An `option` containing the byte index of the last matching character - * or `none` if there is no match - * - * # Failure - * - * `end` must be less than or equal to `start` and `start` must be less - * than or equal to `s.len()`. `start` must be the index of a character - * boundary, as defined by `is_char_boundary` - */ -pub fn rfind_between(s: &str, start: uint, end: uint, f: &fn(char) -> bool) -> Option { - assert!(start >= end); - assert!(start <= s.len()); - assert!(is_char_boundary(s, start)); - let mut i = start; - while i > end { - let CharRange {ch, next: prev} = char_range_at_reverse(s, i); - if f(ch) { return Some(prev); } - i = prev; - } - return None; -} - // Utility used by various searching functions fn match_at<'a,'b>(haystack: &'a str, needle: &'b str, at: uint) -> bool { let mut i = at; @@ -1580,7 +1270,7 @@ pub fn contains<'a,'b>(haystack: &'a str, needle: &'b str) -> bool { * * needle - The char to look for */ pub fn contains_char(haystack: &str, needle: char) -> bool { - find_char(haystack, needle).is_some() + haystack.find(needle).is_some() } /** @@ -2415,11 +2105,9 @@ pub trait StrSlice<'self> { fn rev_iter(&self) -> StrCharRevIterator<'self>; fn bytes_iter(&self) -> StrBytesIterator<'self>; fn bytes_rev_iter(&self) -> StrBytesRevIterator<'self>; - fn split_iter(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep>; - fn splitn_iter(&self, sep: Sep, count: uint) - -> StrCharSplitIterator<'self, Sep>; - fn split_options_iter(&self, sep: Sep, - count: uint, allow_trailing_empty: bool) + fn split_iter(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep>; + fn splitn_iter(&self, sep: Sep, count: uint) -> StrCharSplitIterator<'self, Sep>; + fn split_options_iter(&self, sep: Sep, count: uint, allow_trailing_empty: bool) -> StrCharSplitIterator<'self, Sep>; /// An iterator over the start and end indices of each match of /// `sep` within `self`. @@ -2448,6 +2136,8 @@ pub trait StrSlice<'self> { fn len(&self) -> uint; fn char_len(&self) -> uint; fn slice(&self, begin: uint, end: uint) -> &'self str; + fn slice_from(&self, begin: uint) -> &'self str; + fn slice_to(&self, end: uint) -> &'self str; fn starts_with<'a>(&self, needle: &'a str) -> bool; fn substr(&self, begin: uint, n: uint) -> &'self str; fn escape_default(&self) -> ~str; @@ -2463,6 +2153,9 @@ pub trait StrSlice<'self> { fn char_at(&self, i: uint) -> char; fn char_at_reverse(&self, i: uint) -> char; fn to_bytes(&self) -> ~[u8]; + + fn find(&self, search: C) -> Option; + fn rfind(&self, search: C) -> Option; } /// Extension methods for strings @@ -2500,16 +2193,14 @@ impl<'self> StrSlice<'self> for &'self str { StrBytesRevIterator { it: as_bytes_slice(*self).rev_iter() } } - fn split_iter(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep> { + fn split_iter(&self, sep: Sep) -> StrCharSplitIterator<'self, Sep> { self.split_options_iter(sep, self.len(), true) } - fn splitn_iter(&self, sep: Sep, count: uint) - -> StrCharSplitIterator<'self, Sep> { + fn splitn_iter(&self, sep: Sep, count: uint) -> StrCharSplitIterator<'self, Sep> { self.split_options_iter(sep, count, true) } - fn split_options_iter(&self, sep: Sep, - count: uint, allow_trailing_empty: bool) + fn split_options_iter(&self, sep: Sep, count: uint, allow_trailing_empty: bool) -> StrCharSplitIterator<'self, Sep> { let only_ascii = sep.only_ascii(); StrCharSplitIterator { @@ -2590,6 +2281,14 @@ impl<'self> StrSlice<'self> for &'self str { unsafe { raw::slice_bytes(*self, begin, end) } } #[inline] + fn slice_from(&self, begin: uint) -> &'self str { + self.slice(begin, self.len()) + } + #[inline] + fn slice_to(&self, end: uint) -> &'self str { + self.slice(0, end) + } + #[inline] fn starts_with<'a>(&self, needle: &'a str) -> bool { starts_with(*self, needle) } @@ -2654,6 +2353,54 @@ impl<'self> StrSlice<'self> for &'self str { } fn to_bytes(&self) -> ~[u8] { to_bytes(*self) } + + /** + * Returns the byte index of the first character of `self` that matches `search` + * + * # Return value + * + * `Some` containing the byte index of the last matching character + * or `None` if there is no match + */ + fn find(&self, search: C) -> Option { + if search.only_ascii() { + for self.bytes_iter().enumerate().advance |(i, b)| { + if search.matches(b as char) { return Some(i) } + } + } else { + let mut index = 0; + for self.iter().advance |c| { + if search.matches(c) { return Some(index); } + index += c.len_utf8_bytes(); + } + } + + None + } + /** + * Returns the byte index of the last character of `self` that matches `search` + * + * # Return value + * + * `Some` containing the byte index of the last matching character + * or `None` if there is no match + */ + fn rfind(&self, search: C) -> Option { + let mut index = self.len(); + if search.only_ascii() { + for self.bytes_rev_iter().advance |b| { + index -= 1; + if search.matches(b as char) { return Some(index); } + } + } else { + for self.rev_iter().advance |c| { + index -= c.len_utf8_bytes(); + if search.matches(c) { return Some(index); } + } + } + + None + } } #[allow(missing_doc)] @@ -2803,12 +2550,23 @@ mod tests { } #[test] - fn test_rfind_char() { - assert_eq!(rfind_char("hello", 'l'), Some(3u)); - assert_eq!(rfind_char("hello", 'o'), Some(4u)); - assert_eq!(rfind_char("hello", 'h'), Some(0u)); - assert!(rfind_char("hello", 'z').is_none()); - assert_eq!(rfind_char("ประเทศไทย中华Việt Nam", '华'), Some(30u)); + fn test_find() { + assert_eq!("hello".find('l'), Some(2u)); + assert_eq!("hello".find(|c:char| c == 'o'), Some(4u)); + assert!("hello".find('x').is_none()); + assert!("hello".find(|c:char| c == 'x').is_none()); + assert_eq!("ประเทศไทย中华Việt Nam".find('华'), Some(30u)); + assert_eq!("ประเทศไทย中华Việt Nam".find(|c: char| c == '华'), Some(30u)); + } + + #[test] + fn test_rfind() { + assert_eq!("hello".rfind('l'), Some(3u)); + assert_eq!("hello".rfind(|c:char| c == 'o'), Some(4u)); + assert!("hello".rfind('x').is_none()); + assert!("hello".rfind(|c:char| c == 'x').is_none()); + assert_eq!("ประเทศไทย中华Việt Nam".rfind('华'), Some(30u)); + assert_eq!("ประเทศไทย中华Việt Nam".rfind(|c: char| c == '华'), Some(30u)); } #[test] @@ -3122,6 +2880,19 @@ mod tests { "中华Việt Nam".slice(0u, 2u); } + #[test] + fn test_slice_from() { + assert_eq!("abcd".slice_from(0), "abcd"); + assert_eq!("abcd".slice_from(2), "cd"); + assert_eq!("abcd".slice_from(4), ""); + } + #[test] + fn test_slice_to() { + assert_eq!("abcd".slice_to(0), ""); + assert_eq!("abcd".slice_to(2), "ab"); + assert_eq!("abcd".slice_to(4), "abcd"); + } + #[test] fn test_trim_left_chars() { assert!(trim_left_chars(" *** foo *** ", []) == " *** foo *** "); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 52f6e458db3..68403b2c608 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -24,7 +24,6 @@ source code snippets, etc. use core::prelude::*; use core::cmp; -use core::str; use core::to_bytes; use core::uint; use extra::serialize::{Encodable, Decodable, Encoder, Decoder}; @@ -288,11 +287,11 @@ impl FileMap { pub fn get_line(&self, line: int) -> ~str { let begin: BytePos = self.lines[line] - self.start_pos; let begin = begin.to_uint(); - let end = match str::find_char_from(*self.src, '\n', begin) { - Some(e) => e, - None => self.src.len() - }; - self.src.slice(begin, end).to_owned() + let slice = self.src.slice_from(begin); + match slice.find('\n') { + Some(e) => slice.slice_to(e).to_owned(), + None => slice.to_owned() + } } pub fn record_multibyte_char(&self, pos: BytePos, bytes: uint) {