Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Lint: Consecutive String push #6926

Closed
camsteffen opened this issue Mar 17, 2021 · 2 comments
Closed

New Lint: Consecutive String push #6926

camsteffen opened this issue Mar 17, 2021 · 2 comments
Labels
A-lint Area: New lints E-medium Call for participation: Medium difficulty level problem and requires some initial experience.

Comments

@camsteffen
Copy link
Contributor

camsteffen commented Mar 17, 2021

What it does

Finds consecutive push or push_str operations to a String. These can be combined into a write! macro call.

Categories

  • Kind: perf

What is the advantage of the recommended code over the original code

  • More performant since the String will pre-allocate
  • More concise

Drawbacks

None.

Example

let mut s = String::new();
s.push('h');
s.push_str(ello);
s.push(' ');
s.push_str("world");

Could be written as:

let mut s = String::new();
write!(&mut s, "h{} world", ello);
@camsteffen camsteffen added A-lint Area: New lints E-medium Call for participation: Medium difficulty level problem and requires some initial experience. labels Mar 17, 2021
@camsteffen camsteffen changed the title New Lint: Consective String push New Lint: Consecutive String push Mar 17, 2021
@matthiaskrgr
Copy link
Member

I tried to benchmark this

#![feature(test)]

extern crate test;
use std::fmt::Write;
fn main() {}

#[cfg(test)]
mod tests {
    use std::fmt::Write;
    use test::Bencher;

    pub fn push_str() -> String {
        let mut s = String::new();
        s.push('h');
        s.push_str("ello");
        s.push_str(" world");
        s
    }

    pub fn write() -> String {
        let mut s = String::new();
        write!(&mut s, "h{} world", "ello").unwrap();
        s
    }

    const ITERATIONS: i32 = 750;

    #[bench]
    fn bench_push_str(b: &mut Bencher) {
        b.iter(|| {
            for _ in 1..ITERATIONS {
                let _ = push_str();
            }
        });
    }

    #[bench]
    fn bench_write(b: &mut Bencher) {
        b.iter(|| {
            for _ in 1..ITERATIONS {
                let _ = write();
            }
        });
    }
}

and on my system the push variant was consistently faster:

running 2 tests
test tests::bench_push_str ... bench:      32,473 ns/iter (+/- 5,530)
test tests::bench_write    ... bench:      45,523 ns/iter (+/- 7,741)

@camsteffen
Copy link
Contributor Author

Hmm you're right. I tried fiddling with the bench and got the same results. Going to close this as it seems like write! is not really advisable in this case.

Related: rust-lang/rust#76490

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints E-medium Call for participation: Medium difficulty level problem and requires some initial experience.
Projects
None yet
Development

No branches or pull requests

2 participants