Skip to content

Commit a6f817f

Browse files
authoredDec 16, 2019
Rollup merge of #67249 - ranma42:improve-starts-with-literal-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 #41993
2 parents f0d4b57 + 3de1923 commit a6f817f

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed
 

‎src/libcore/benches/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ mod hash;
1111
mod iter;
1212
mod num;
1313
mod ops;
14+
mod pattern;
1415
mod slice;

‎src/libcore/benches/pattern.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use test::black_box;
2+
use test::Bencher;
3+
4+
#[bench]
5+
fn starts_with_char(b: &mut Bencher) {
6+
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
7+
b.iter(|| {
8+
for _ in 0..1024 {
9+
black_box(text.starts_with('k'));
10+
}
11+
})
12+
}
13+
14+
#[bench]
15+
fn starts_with_str(b: &mut Bencher) {
16+
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
17+
b.iter(|| {
18+
for _ in 0..1024 {
19+
black_box(text.starts_with("k"));
20+
}
21+
})
22+
}
23+
24+
25+
#[bench]
26+
fn ends_with_char(b: &mut Bencher) {
27+
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
28+
b.iter(|| {
29+
for _ in 0..1024 {
30+
black_box(text.ends_with('k'));
31+
}
32+
})
33+
}
34+
35+
#[bench]
36+
fn ends_with_str(b: &mut Bencher) {
37+
let text = black_box("kdjsfhlakfhlsghlkvcnljknfqiunvcijqenwodind");
38+
b.iter(|| {
39+
for _ in 0..1024 {
40+
black_box(text.ends_with("k"));
41+
}
42+
})
43+
}

‎src/libcore/str/pattern.rs

+4-15
Original file line numberDiff line numberDiff line change
@@ -445,21 +445,13 @@ impl<'a> Pattern<'a> for char {
445445

446446
#[inline]
447447
fn is_prefix_of(self, haystack: &'a str) -> bool {
448-
if let Some(ch) = haystack.chars().next() {
449-
self == ch
450-
} else {
451-
false
452-
}
448+
self.encode_utf8(&mut [0u8; 4]).is_prefix_of(haystack)
453449
}
454450

455451
#[inline]
456452
fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a>
457453
{
458-
if let Some(ch) = haystack.chars().next_back() {
459-
self == ch
460-
} else {
461-
false
462-
}
454+
self.encode_utf8(&mut [0u8; 4]).is_suffix_of(haystack)
463455
}
464456
}
465457

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

717708
/// Checks whether the pattern matches at the back of the haystack
718709
#[inline]
719710
fn is_suffix_of(self, haystack: &'a str) -> bool {
720-
self.len() <= haystack.len() &&
721-
haystack.is_char_boundary(haystack.len() - self.len()) &&
722-
self == &haystack[haystack.len() - self.len()..]
711+
haystack.as_bytes().ends_with(self.as_bytes())
723712
}
724713
}
725714

0 commit comments

Comments
 (0)
Please sign in to comment.