Skip to content

Commit

Permalink
Rollup merge of rust-lang#67249 - ranma42:improve-starts-with-literal…
Browse files Browse the repository at this point in the history
…-char, r=BurntSushi

Improve code generated for `starts_with(<literal char>)`

This PR includes two minor improvements to the code generated when checking for string prefix/suffix.

The first commit simplifies the str/str operation, by taking advantage of the raw UTF-8 representation.

The second commit replaces the current str/char matching logic with a char->str encoding and then the previous method.

The resulting code should be equivalent in the generic case (one char is being encoded versus one char being decoded), but it becomes easy to optimize in the case of a literal char, which in most cases a developer might expect to be at least as simple as that of a literal string.

This PR should fix rust-lang#41993
  • Loading branch information
Centril authored Dec 16, 2019
2 parents 94cb34e + 3de1923 commit 62ff55c
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/libcore/benches/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ mod hash;
mod iter;
mod num;
mod ops;
mod pattern;
mod slice;
43 changes: 43 additions & 0 deletions src/libcore/benches/pattern.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use test::black_box;
use test::Bencher;

#[bench]
fn starts_with_char(b: &mut Bencher) {
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
b.iter(|| {
for _ in 0..1024 {
black_box(text.starts_with('k'));
}
})
}

#[bench]
fn starts_with_str(b: &mut Bencher) {
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
b.iter(|| {
for _ in 0..1024 {
black_box(text.starts_with("k"));
}
})
}


#[bench]
fn ends_with_char(b: &mut Bencher) {
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
b.iter(|| {
for _ in 0..1024 {
black_box(text.ends_with('k'));
}
})
}

#[bench]
fn ends_with_str(b: &mut Bencher) {
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
b.iter(|| {
for _ in 0..1024 {
black_box(text.ends_with("k"));
}
})
}
19 changes: 4 additions & 15 deletions src/libcore/str/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,21 +445,13 @@ impl<'a> Pattern<'a> for char {

#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
if let Some(ch) = haystack.chars().next() {
self == ch
} else {
false
}
self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack)
}

#[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a>
{
if let Some(ch) = haystack.chars().next_back() {
self == ch
} else {
false
}
self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack)
}
}

Expand Down Expand Up @@ -710,16 +702,13 @@ impl<'a, 'b> Pattern<'a> for &'b str {
/// Checks whether the pattern matches at the front of the haystack
#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
haystack.is_char_boundary(self.len()) &&
self == &haystack[..self.len()]
haystack.as_bytes().starts_with(self.as_bytes())
}

/// Checks whether the pattern matches at the back of the haystack
#[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool {
self.len() <= haystack.len() &&
haystack.is_char_boundary(haystack.len() - self.len()) &&
self == &haystack[haystack.len() - self.len()..]
haystack.as_bytes().ends_with(self.as_bytes())
}
}

Expand Down

0 comments on commit 62ff55c

Please sign in to comment.