Skip to content

Commit

Permalink
Rollup merge of rust-lang#42037 - nagisa:charpat, r=sfackler
Browse files Browse the repository at this point in the history
Minor optimisation of the string operations

The interesting benchmarks are

<table cellspacing="0" border="0">
	<tr>
		<th height="17" align="right"><b> (&lt;100% → better than original )</b></th>
		<th align="left" sdnum="2057;0;0.00%">Delta</th>
		<th align="left">Original ns/i</th>
		<th align="left">This Patch ns/i</th>
	</tr>
	<tr>
		<td height="17" align="left">str::contains_bang_char::long_lorem_ipsum</td>
		<td align="right" sdval="0.249775381850854" sdnum="2057;0;0.00%">24.98%</td>
		<td align="right" sdval="5565" sdnum="2057;">5565</td>
		<td align="right" sdval="1390" sdnum="2057;">1390</td>
	</tr>
	<tr>
		<td height="17" align="left">str::contains_bang_char::short_ascii</td>
		<td align="right" sdval="0.277777777777778" sdnum="2057;0;0.00%">27.78%</td>
		<td align="right" sdval="144" sdnum="2057;">144</td>
		<td align="right" sdval="40" sdnum="2057;">40</td>
	</tr>
	<tr>
		<td height="17" align="left">str::contains_bang_char::short_mixed</td>
		<td align="right" sdval="0.333333333333333" sdnum="2057;0;0.00%">33.33%</td>
		<td align="right" sdval="120" sdnum="2057;">120</td>
		<td align="right" sdval="40" sdnum="2057;">40</td>
	</tr>
	<tr>
		<td height="17" align="left">str::contains_bang_char::short_pile_of_poo</td>
		<td align="right" sdval="0.594202898550725" sdnum="2057;0;0.00%">59.42%</td>
		<td align="right" sdval="69" sdnum="2057;">69</td>
		<td align="right" sdval="41" sdnum="2057;">41</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_ascii_char::long_lorem_ipsum</td>
		<td align="right" sdval="0.452629649990837" sdnum="2057;0;0.00%">45.26%</td>
		<td align="right" sdval="5457" sdnum="2057;">5457</td>
		<td align="right" sdval="2470" sdnum="2057;">2470</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_ascii_char::short_ascii</td>
		<td align="right" sdval="0.450054684651841" sdnum="2057;0;0.00%">45.01%</td>
		<td align="right" sdval="5486" sdnum="2057;">5486</td>
		<td align="right" sdval="2469" sdnum="2057;">2469</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_ascii_char::short_mixed</td>
		<td align="right" sdval="0.463132795304475" sdnum="2057;0;0.00%">46.31%</td>
		<td align="right" sdval="5452" sdnum="2057;">5452</td>
		<td align="right" sdval="2525" sdnum="2057;">2525</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_ascii_char::short_pile_of_poo</td>
		<td align="right" sdval="0.453426419254088" sdnum="2057;0;0.00%">45.34%</td>
		<td align="right" sdval="5443" sdnum="2057;">5443</td>
		<td align="right" sdval="2468" sdnum="2057;">2468</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_unichar::long_lorem_ipsum</td>
		<td align="right" sdval="0.459385290889133" sdnum="2057;0;0.00%">45.94%</td>
		<td align="right" sdval="5466" sdnum="2057;">5466</td>
		<td align="right" sdval="2511" sdnum="2057;">2511</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_unichar::short_ascii</td>
		<td align="right" sdval="0.460593841642229" sdnum="2057;0;0.00%">46.06%</td>
		<td align="right" sdval="5456" sdnum="2057;">5456</td>
		<td align="right" sdval="2513" sdnum="2057;">2513</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_unichar::short_mixed</td>
		<td align="right" sdval="0.454976303317536" sdnum="2057;0;0.00%">45.50%</td>
		<td align="right" sdval="5486" sdnum="2057;">5486</td>
		<td align="right" sdval="2496" sdnum="2057;">2496</td>
	</tr>
	<tr>
		<td height="17" align="left">str::ends_with_unichar::short_pile_of_poo</td>
		<td align="right" sdval="0.456497797356828" sdnum="2057;0;0.00%">45.65%</td>
		<td align="right" sdval="5448" sdnum="2057;">5448</td>
		<td align="right" sdval="2487" sdnum="2057;">2487</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_underscore_char::long_lorem_ipsum</td>
		<td align="right" sdval="0.622058559367703" sdnum="2057;0;0.00%">62.21%</td>
		<td align="right" sdval="5567" sdnum="2057;">5567</td>
		<td align="right" sdval="3463" sdnum="2057;">3463</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_underscore_char::short_ascii</td>
		<td align="right" sdval="0.664383561643836" sdnum="2057;0;0.00%">66.44%</td>
		<td align="right" sdval="146" sdnum="2057;">146</td>
		<td align="right" sdval="97" sdnum="2057;">97</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_underscore_char::short_mixed</td>
		<td align="right" sdval="0.762295081967213" sdnum="2057;0;0.00%">76.23%</td>
		<td align="right" sdval="122" sdnum="2057;">122</td>
		<td align="right" sdval="93" sdnum="2057;">93</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_underscore_str::short_pile_of_poo</td>
		<td align="right" sdval="0.476190476190476" sdnum="2057;0;0.00%">47.62%</td>
		<td align="right" sdval="252" sdnum="2057;">252</td>
		<td align="right" sdval="120" sdnum="2057;">120</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_zzz_char::long_lorem_ipsum</td>
		<td align="right" sdval="0.621655593463818" sdnum="2057;0;0.00%">62.17%</td>
		<td align="right" sdval="5569" sdnum="2057;">5569</td>
		<td align="right" sdval="3462" sdnum="2057;">3462</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_zzz_char::short_ascii</td>
		<td align="right" sdval="0.666666666666667" sdnum="2057;0;0.00%">66.67%</td>
		<td align="right" sdval="147" sdnum="2057;">147</td>
		<td align="right" sdval="98" sdnum="2057;">98</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_zzz_char::short_mixed</td>
		<td align="right" sdval="0.754098360655738" sdnum="2057;0;0.00%">75.41%</td>
		<td align="right" sdval="122" sdnum="2057;">122</td>
		<td align="right" sdval="92" sdnum="2057;">92</td>
	</tr>
	<tr>
		<td height="17" align="left">str::find_zzz_str::long_lorem_ipsum</td>
		<td align="right" sdval="0.728648648648649" sdnum="2057;0;0.00%">72.86%</td>
		<td align="right" sdval="925" sdnum="2057;">925</td>
		<td align="right" sdval="674" sdnum="2057;">674</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_underscore_char::long_lorem_ipsum</td>
		<td align="right" sdval="0.3418911335578" sdnum="2057;0;0.00%">34.19%</td>
		<td align="right" sdval="7128" sdnum="2057;">7128</td>
		<td align="right" sdval="2437" sdnum="2057;">2437</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_underscore_char::short_ascii</td>
		<td align="right" sdval="0.373056994818653" sdnum="2057;0;0.00%">37.31%</td>
		<td align="right" sdval="193" sdnum="2057;">193</td>
		<td align="right" sdval="72" sdnum="2057;">72</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_underscore_char::short_mixed</td>
		<td align="right" sdval="0.414201183431953" sdnum="2057;0;0.00%">41.42%</td>
		<td align="right" sdval="169" sdnum="2057;">169</td>
		<td align="right" sdval="70" sdnum="2057;">70</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_underscore_char::short_pile_of_poo</td>
		<td align="right" sdval="0.505050505050505" sdnum="2057;0;0.00%">50.51%</td>
		<td align="right" sdval="99" sdnum="2057;">99</td>
		<td align="right" sdval="50" sdnum="2057;">50</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_zzz_char::long_lorem_ipsum</td>
		<td align="right" sdval="0.341983447888904" sdnum="2057;0;0.00%">34.20%</td>
		<td align="right" sdval="7129" sdnum="2057;">7129</td>
		<td align="right" sdval="2438" sdnum="2057;">2438</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_zzz_char::short_ascii</td>
		<td align="right" sdval="0.371134020618557" sdnum="2057;0;0.00%">37.11%</td>
		<td align="right" sdval="194" sdnum="2057;">194</td>
		<td align="right" sdval="72" sdnum="2057;">72</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_zzz_char::short_mixed</td>
		<td align="right" sdval="0.409356725146199" sdnum="2057;0;0.00%">40.94%</td>
		<td align="right" sdval="171" sdnum="2057;">171</td>
		<td align="right" sdval="70" sdnum="2057;">70</td>
	</tr>
	<tr>
		<td height="17" align="left">str::rfind_zzz_char::short_pile_of_poo</td>
		<td align="right" sdval="0.548076923076923" sdnum="2057;0;0.00%">54.81%</td>
		<td align="right" sdval="104" sdnum="2057;">104</td>
		<td align="right" sdval="57" sdnum="2057;">57</td>
	</tr>
	<tr>
		<td height="17" align="left">str::trim_right_ascii_char::short_mixed</td>
		<td align="right" sdval="1.10416666666667" sdnum="2057;0;0.00%">110.42%</td>
		<td align="right" sdval="48" sdnum="2057;">48</td>
		<td align="right" sdval="53" sdnum="2057;">53</td>
	</tr>
	<tr>
		<td height="17" align="left">string::bench_from</td>
		<td align="right" sdval="1.17241379310345" sdnum="2057;0;0.00%">117.24%</td>
		<td align="right" sdval="58" sdnum="2057;">58</td>
		<td align="right" sdval="68" sdnum="2057;">68</td>
	</tr>
	<tr>
		<td height="17" align="left">string::bench_from_str</td>
		<td align="right" sdval="1.17241379310345" sdnum="2057;0;0.00%">117.24%</td>
		<td align="right" sdval="58" sdnum="2057;">58</td>
		<td align="right" sdval="68" sdnum="2057;">68</td>
	</tr>
	<tr>
		<td height="17" align="left">string::bench_push_str</td>
		<td align="right" sdval="1.11111111111111" sdnum="2057;0;0.00%">111.11%</td>
		<td align="right" sdval="54" sdnum="2057;">54</td>
		<td align="right" sdval="60" sdnum="2057;">60</td>
	</tr>
	<tr>
		<td height="17" align="left">string::bench_to_string</td>
		<td align="right" sdval="1.12068965517241" sdnum="2057;0;0.00%">112.07%</td>
		<td align="right" sdval="58" sdnum="2057;">58</td>
		<td align="right" sdval="65" sdnum="2057;">65</td>
	</tr>
	<tr>
		<td height="17" align="left">string::from_utf8_lossy_100_invalid</td>
		<td align="right" sdval="1.1131458469588" sdnum="2057;0;0.00%">111.31%</td>
		<td align="right" sdval="1529" sdnum="2057;">1529</td>
		<td align="right" sdval="1702" sdnum="2057;">1702</td>
	</tr>
</table>
  • Loading branch information
Mark-Simulacrum committed May 19, 2017
2 parents 862e7d4 + 41debc3 commit db01c94
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 7 deletions.
23 changes: 17 additions & 6 deletions src/libcollections/benches/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,30 +195,34 @@ fn bench_contains_equal(b: &mut Bencher) {
})
}


macro_rules! make_test_inner {
($s:ident, $code:expr, $name:ident, $str:expr) => {
($s:ident, $code:expr, $name:ident, $str:expr, $iters:expr) => {
#[bench]
fn $name(bencher: &mut Bencher) {
let mut $s = $str;
black_box(&mut $s);
bencher.iter(|| $code);
bencher.iter(|| for _ in 0..$iters { black_box($code); });
}
}
}

macro_rules! make_test {
($name:ident, $s:ident, $code:expr) => {
make_test!($name, $s, $code, 1);
};
($name:ident, $s:ident, $code:expr, $iters:expr) => {
mod $name {
use test::Bencher;
use test::black_box;

// Short strings: 65 bytes each
make_test_inner!($s, $code, short_ascii,
"Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!");
"Mary had a little lamb, Little lamb Mary had a littl lamb, lamb!", $iters);
make_test_inner!($s, $code, short_mixed,
"ศไทย中华Việt Nam; Mary had a little lamb, Little lam!");
"ศไทย中华Việt Nam; Mary had a little lamb, Little lam!", $iters);
make_test_inner!($s, $code, short_pile_of_poo,
"💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!");
"💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩!", $iters);
make_test_inner!($s, $code, long_lorem_ipsum,"\
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \
ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \
Expand Down Expand Up @@ -253,7 +257,7 @@ Nam lectus enim, dapibus non nisi tempor, consectetur convallis massa. Maecenas
feugiat. Etiam quis mauris vel risus luctus mattis a a nunc. Nullam orci quam, imperdiet id \
vehicula in, porttitor ut nibh. Duis sagittis adipiscing nisl vitae congue. Donec mollis risus eu \
leo suscipit, varius porttitor nulla porta. Pellentesque ut sem nec nisi euismod vehicula. Nulla \
malesuada sollicitudin quam eu fermentum!");
malesuada sollicitudin quam eu fermentum!", $iters);
}
}
}
Expand Down Expand Up @@ -288,6 +292,13 @@ make_test!(find_zzz_char, s, s.find('\u{1F4A4}'));
make_test!(rfind_zzz_char, s, s.rfind('\u{1F4A4}'));
make_test!(find_zzz_str, s, s.find("\u{1F4A4}"));

make_test!(starts_with_ascii_char, s, s.starts_with('/'), 1024);
make_test!(ends_with_ascii_char, s, s.ends_with('/'), 1024);
make_test!(starts_with_unichar, s, s.starts_with('\u{1F4A4}'), 1024);
make_test!(ends_with_unichar, s, s.ends_with('\u{1F4A4}'), 1024);
make_test!(starts_with_str, s, s.starts_with("💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩"), 1024);
make_test!(ends_with_str, s, s.ends_with("💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩💩"), 1024);

make_test!(split_space_char, s, s.split(' ').count());
make_test!(split_terminator_space_char, s, s.split_terminator(' ').count());

Expand Down
14 changes: 14 additions & 0 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ impl str {
/// assert!(!bananas.contains("apples"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
core_str::StrExt::contains(self, pat)
}
Expand Down Expand Up @@ -900,6 +901,7 @@ impl str {
/// assert_eq!(s.find(x), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
core_str::StrExt::find(self, pat)
}
Expand Down Expand Up @@ -944,6 +946,7 @@ impl str {
/// assert_eq!(s.rfind(x), None);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1057,6 +1060,7 @@ impl str {
///
/// [`split_whitespace`]: #method.split_whitespace
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
core_str::StrExt::split(self, pat)
}
Expand Down Expand Up @@ -1106,6 +1110,7 @@ impl str {
/// assert_eq!(v, ["ghi", "def", "abc"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1152,6 +1157,7 @@ impl str {
/// assert_eq!(v, ["A", "", "B", ""]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> {
core_str::StrExt::split_terminator(self, pat)
}
Expand Down Expand Up @@ -1195,6 +1201,7 @@ impl str {
/// assert_eq!(v, ["", "B", "", "A"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1247,6 +1254,7 @@ impl str {
/// assert_eq!(v, ["abc", "defXghi"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> {
core_str::StrExt::splitn(self, n, pat)
}
Expand Down Expand Up @@ -1294,6 +1302,7 @@ impl str {
/// assert_eq!(v, ["ghi", "abc1def"]);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1334,6 +1343,7 @@ impl str {
/// assert_eq!(v, ["1", "2", "3"]);
/// ```
#[stable(feature = "str_matches", since = "1.2.0")]
#[inline]
pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> {
core_str::StrExt::matches(self, pat)
}
Expand Down Expand Up @@ -1370,6 +1380,7 @@ impl str {
/// assert_eq!(v, ["3", "2", "1"]);
/// ```
#[stable(feature = "str_matches", since = "1.2.0")]
#[inline]
pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1415,6 +1426,7 @@ impl str {
/// assert_eq!(v, [(0, "aba")]); // only the first `aba`
/// ```
#[stable(feature = "str_match_indices", since = "1.5.0")]
#[inline]
pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> {
core_str::StrExt::match_indices(self, pat)
}
Expand Down Expand Up @@ -1457,6 +1469,7 @@ impl str {
/// assert_eq!(v, [(2, "aba")]); // only the last `aba`
/// ```
#[stable(feature = "str_match_indices", since = "1.5.0")]
#[inline]
pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P>
where P::Searcher: ReverseSearcher<'a>
{
Expand Down Expand Up @@ -1737,6 +1750,7 @@ impl str {
/// assert_eq!(s, s.replace("cookie monster", "little lamb"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String {
let mut result = String::new();
let mut last_end = 0;
Expand Down
28 changes: 27 additions & 1 deletion src/libcore/str/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,33 @@ impl<'a> DoubleEndedSearcher<'a> for CharSearcher<'a> {}

/// Searches for chars that are equal to a given char
impl<'a> Pattern<'a> for char {
pattern_methods!(CharSearcher<'a>, CharEqPattern, CharSearcher);
type Searcher = CharSearcher<'a>;

#[inline]
fn into_searcher(self, haystack: &'a str) -> Self::Searcher {
CharSearcher(CharEqPattern(self).into_searcher(haystack))
}

#[inline]
fn is_contained_in(self, haystack: &'a str) -> bool {
if (self as u32) < 128 {
haystack.as_bytes().contains(&(self as u8))
} else {
let mut buffer = [0u8; 4];
self.encode_utf8(&mut buffer).is_contained_in(haystack)
}
}

#[inline]
fn is_prefix_of(self, haystack: &'a str) -> bool {
CharEqPattern(self).is_prefix_of(haystack)
}

#[inline]
fn is_suffix_of(self, haystack: &'a str) -> bool where Self::Searcher: ReverseSearcher<'a>
{
CharEqPattern(self).is_suffix_of(haystack)
}
}

/////////////////////////////////////////////////////////////////////////////
Expand Down

0 comments on commit db01c94

Please sign in to comment.