rust-lang / rust-lang/rust-clippy

single_char_pattern lint suggests performance regression for strip_prefix/suffix

Open
#8,111 3 comments 3 reactions 1 assignee View on GitHub

@llogiq is already working on this.

Since Nov 10, 2023.

C-bug I-false-positive
Dominant language
Rust
Stars
13.5k
Forks
2.2k
Avg merge
2d 10h
Merged PRs (30d)
32

Description

Summary

The lint single_char_pattern suggest replacing a string with a char constant, but this actually results in significantly worse performance for wide Unicode characters in strip_prefix.

In some sense this is a rust standard library issue, but clippy shouldn't suggest this as an improvement and say "Performing these methods using a char is faster than using a str." when the opposite is true.

This seems to be the case for strip_prefix and strip_suffix. For other methods like split, char is always faster than str.

Simplest fix: remove strip_prefix and strip_suffix from the list of functions to check in this lint.

Lint Name

single_char_pattern

Reproducer

Here is a benchmark:

use criterion::{black_box, criterion_group, criterion_main, Criterion};
pub fn criterion_benchmark(c: &mut Criterion) {
  c.bench_function("strip_prefix str  ascii",   |b| b.iter(|| black_box("hello world").strip_prefix("h")));
  c.bench_function("strip_prefix char ascii",   |b| b.iter(|| black_box("hello world").strip_prefix('h')));
  c.bench_function("strip_prefix str  unicode", |b| b.iter(|| black_box("おはよう、世界").strip_prefix("お")));
  c.bench_function("strip_prefix char unicode", |b| b.iter(|| black_box("おはよう、世界").strip_prefix('お')));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);

For which clippy reports:

warning: single-character string constant used as pattern
 --> src\main.rs:4:101
  |
4 |   c.bench_function("strip_prefix str  ascii",   |b| b.iter(|| black_box("hello world").strip_prefix("h")));
  |                                                                                                     ^^^ help: try using a `char` instead: `'h'`
  |
  = note: `#[warn(clippy::single_char_pattern)]` on by default
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern

warning: single-character string constant used as pattern
 --> src\main.rs:6:97
  |
6 |   c.bench_function("strip_prefix str  unicode", |b| b.iter(|| black_box("おはよう、世界").strip_prefix("お")));
  |                                                                                                        ^^^^ help: try using a `char` instead: `'お'`
  |
  = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern

The documentation says "Performing these methods using a char is faster than using a str."

Benchmark output:

strip_prefix str  ascii time:   [4.3805 ns 4.4939 ns 4.6732 ns]
strip_prefix char ascii time:   [4.2060 ns 4.2173 ns 4.2305 ns]
strip_prefix str  unicode
                        time:   [4.7124 ns 4.7187 ns 4.7270 ns]
strip_prefix char unicode
                        time:   [11.643 ns 11.677 ns 11.715 ns]

The performance with a single character Unicode pattern is better with a string pattern than with a char pattern. So clippy shouldn't suggest this change.

Version
rustc 1.59.0-nightly (efec54529 2021-12-04)
binary: rustc
commit-hash: efec545293b9263be9edfb283a7aa66350b3acbf
commit-date: 2021-12-04
host: x86_64-pc-windows-msvc
release: 1.59.0-nightly
LLVM version: 13.0.0
Additional Labels

No response

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.