Skip to content

Commit 3e5257f

Browse files
committed
rollup merge of rust-lang#20079: SimonSapin/string_push_ascii_fast_path
`String::push(&mut self, ch: char)` currently has a single code path that calls `Char::encode_utf8`. This adds a fast path for ASCII `char`s, which are represented as a single byte in UTF-8. Benchmarks of stage1 libcollections at the intermediate commit show that the fast path very significantly improves the performance of repeatedly pushing an ASCII `char`, but does not significantly affect the performance for a non-ASCII `char` (where the fast path is not taken). ``` bench_push_char_one_byte 59552 ns/iter (+/- 2132) = 167 MB/s bench_push_char_one_byte_with_fast_path 6563 ns/iter (+/- 658) = 1523 MB/s bench_push_char_two_bytes 71520 ns/iter (+/- 3541) = 279 MB/s bench_push_char_two_bytes_with_slow_path 71452 ns/iter (+/- 4202) = 279 MB/s bench_push_str_one_byte 38910 ns/iter (+/- 2477) = 257 MB/s ``` A benchmark of pushing a one-byte-long `&str` is added for comparison, but its performance [has varied a lot lately](rust-lang#19640 (comment)). (When the input is fixed, `s.push_str("x")` could be used just as well as `s.push('x')`.)
2 parents 0191dce + e40a81b commit 3e5257f

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

src/libcollections/string.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,11 @@ impl String {
513513
#[inline]
514514
#[stable = "function just renamed from push_char"]
515515
pub fn push(&mut self, ch: char) {
516+
if (ch as u32) < 0x80 {
517+
self.vec.push(ch as u8);
518+
return;
519+
}
520+
516521
let cur_len = self.len();
517522
// This may use up to 4 bytes.
518523
self.vec.reserve(4);
@@ -1401,6 +1406,41 @@ mod tests {
14011406
});
14021407
}
14031408

1409+
const REPETITIONS: u64 = 10_000;
1410+
1411+
#[bench]
1412+
fn bench_push_str_one_byte(b: &mut Bencher) {
1413+
b.bytes = REPETITIONS;
1414+
b.iter(|| {
1415+
let mut r = String::new();
1416+
for _ in range(0, REPETITIONS) {
1417+
r.push_str("a")
1418+
}
1419+
});
1420+
}
1421+
1422+
#[bench]
1423+
fn bench_push_char_one_byte(b: &mut Bencher) {
1424+
b.bytes = REPETITIONS;
1425+
b.iter(|| {
1426+
let mut r = String::new();
1427+
for _ in range(0, REPETITIONS) {
1428+
r.push('a')
1429+
}
1430+
});
1431+
}
1432+
1433+
#[bench]
1434+
fn bench_push_char_two_bytes(b: &mut Bencher) {
1435+
b.bytes = REPETITIONS * 2;
1436+
b.iter(|| {
1437+
let mut r = String::new();
1438+
for _ in range(0, REPETITIONS) {
1439+
r.push('â')
1440+
}
1441+
});
1442+
}
1443+
14041444
#[bench]
14051445
fn from_utf8_lossy_100_ascii(b: &mut Bencher) {
14061446
let s = b"Hello there, the quick brown fox jumped over the lazy dog! \

0 commit comments

Comments
 (0)